• SPOJ COT(树上的点权第k大)


    Time Limit: 129MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

     Status

    Description

    You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

    We will ask you to perform the following operation:

    • u v k : ask for the kth minimum weight on the path from node u to node v

    Input

    In the first line there are two integers N and M.(N,M<=100000)

    In the second line there are N integers.The ith integer denotes the weight of the ith node.

    In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

    In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.

    Output

    For each operation,print its result.

    Example

    Input:
    8 5
    8 5
    105 2 9 3 8 5 7 7
    1 2        
    1 3
    1 4
    3 5
    3 6
    3 7
    4 8
    2 5 1
    2 5 2
    2 5 3
    2 5 4
    7 8 2 
    Output:
    2
    8
    9
    105
    7 

    题意:求树上的边[u,v]中点权第k大

    使用的是主席树+LCA(RMQ.dfs),然后去专门看了下RMQ+dfs实现LCA

    用一个数组记录深度,然后记录搜索的路径,如果要找[a,b]中的LCA,直接找[a,b]中的深度最小值即可

    参考:算法之LCA与RMQ问题


    /*
    主席树-代码参考kuangbin大神
    在本题中相当于按树的节点来构建线段树,每个节点基于它的父亲进行构建
    然后节点a保存的便是根到a的情况,于是乎我们T[a]+T[b]-2*T[lca(a,b)]即可
    而且对lca节点进行一个判断。
    hhh-2016-02-18 21:11:14
    */
    
    #include <functional>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    using namespace std;
    
    const int maxn = 200010;
    int n,m;
    int a[maxn],t[maxn];
    int T[maxn*40],val[maxn*40],lson[maxn*40],rson[maxn*40];
    int Tot;
    
    void ini_hash() //排序去重
    {
        for(int i =1; i <= n; i++)
            t[i] = a[i];
        sort(t+1,t+n+1);
        m = unique(t+1,t+n+1)-t-1;
    }
    
    int Hash(int x) //获得x在排序去重后的位置
    {
        return lower_bound(t+1,t+m+1,x) - t;
    }
    
    int build(int l,int r)
    {
        int root = Tot++;
        val[root] = 0;
        if(l != r)
        {
            int mid = (l+r)>>1;
            lson[root] = build(l,mid);
            rson[root] = build(mid+1,r);
        }
        return root;
    }
    
    
    //如果那里发生改变则兴建一个节点而非像平常修改那个节点的值
    int update(int root,int pos,int va)
    {
        int newroot = Tot++;
        int tmp = newroot;
        val[newroot] = val[root] + va;
        int l = 1,r = m;
        while(l < r)
        {
            int mid = (l+r)>>1;
            if(pos <= mid)
            {
                lson[newroot] = Tot++;
                rson[newroot] = rson[root];
                newroot = lson[newroot];
                root = lson[root];
                r = mid;
            }
            else
            {
                lson[newroot] = lson[root];
                rson[newroot] = Tot++;
                newroot = rson[newroot];
                root = rson[root];
                l = mid+1;
            }
            val[newroot] = val[root] + va;
        }
        return tmp;
    }
    
    int query(int lt,int rt,int lca,int k)
    {
        int lca_rt = T[lca];
        int pos = Hash(a[lca]);
        int l = 1, r = m;
        while(l < r)
        {
            int mid = (l+r)>>1;
            int tmp = val[lson[lt]]+val[lson[rt]]-2*val[lson[lca_rt]]+(pos>=l&&pos<=mid);
            if(tmp >= k)
            {
                lt = lson[lt];
                rt = lson[rt];
                lca_rt = lson[lca_rt];
                r = mid;
            }
            else
            {
                k -= tmp;
                l = mid+1;
                lt = rson[lt];
                rt = rson[rt];
                lca_rt = rson[lca_rt];
            }
        }
        return l;
    }
    
    int rmq[maxn*2]; //表示深度
    struct ST
    {
        int mm[maxn*2];
        int dp[maxn*2][20];
        void ini(int n)
        {
            mm[0] = -1;
            for(int i = 1; i <= n; i++)
            {
                mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
                dp[i][0] = i;
            }
            for(int j = 1; j <= mm[n]; j++)
                for(int i = 1; i + (1<<j) - 1 <= n; i++)
                    dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?
                               dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
        int query(int a,int b)
        {
            if(a > b)swap(a,b);
            int k = mm[b-a+1];
            return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?
                   dp[a][k]:dp[b-(1<<k)+1][k];
        }
    };
    
    struct E
    {
        int to,next;
    } edge[maxn*2];
    int tot,head[maxn];
    int F[maxn*2];
    int P[maxn];
    int cnt;
    //F表示dfs的序列
    //P[i]表示i第一次出现的位置
    
    ST st;
    void init() //初始化
    {
        Tot = tot = 0;
        memset(head,-1,sizeof(head));
    }
    
    void dfs(int u,int pre,int dep)
    {
        F[++cnt] = u;
        rmq[cnt] = dep;
        P[u] = cnt;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == pre)continue;
            dfs(v,u,dep+1);
            F[++cnt] = u;
            rmq[cnt] = dep;
        }
    }
    
    
    void ini_lca(int root,int num)
    {
        cnt = 0;
        dfs(root,root,0);
        st.ini(2*num-1);
    }
    
    void addedge(int u,int v)
    {
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    int query_lca(int u,int v)
    {
        return F[st.query(P[u],P[v])];
    }
    
    void dfs_build(int u,int pre)
    {
        int pos = Hash(a[u]);
        T[u] = update(T[pre],pos,1);
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(v == pre) continue;
            dfs_build(v,u);
        }
    }
    
    int main()
    {
        int q;
        while(scanf("%d%d",&n,&q) == 2)
        {
            for(int i = 1; i <= n; i++)
                scanf("%d",&a[i]);
            ini_hash();
            init();
            int u,v,k;
            for(int i = 1; i < n; i++)
            {
    
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
            }
            ini_lca(1,n);
            T[n+1] = build(1,m);
            dfs_build(1,n+1);
            while(q--)
            {
                scanf("%d%d%d",&u,&v,&k);
                printf("%d
    ",t[query(T[u],T[v],query_lca(u,v),k)]);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    第一阶段冲刺09
    英文单词统计
    第一阶段冲刺08
    暑假生活第二周
    暑假生活第一周
    大道至简读书笔记03
    个人总结15
    大道至简读书笔记02
    计算最长英语单词链
    个人总结14
  • 原文地址:https://www.cnblogs.com/Przz/p/5409626.html
Copyright © 2020-2023  润新知