zoukankan      html  css  js  c++  java
  • SPOJ PT07J

    PT07J - Query on a tree III

    You are given a node-labeled rooted tree with n nodes.

    Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels.

    Input

    The first line contains one integer n (1 <= n <= 105). The next line contains n integers li (0 <= li <= 109) which denotes the label of the i-th node.

    Each line of the following n - 1 lines contains two integers u, v. They denote there is an edge between node u and node v. Node 1 is the root of the tree.

    The next line contains one integer m (1 <= m <= 104) which denotes the number of the queries. Each line of the next m contains two integers x, k. (k <= the total node number in the subtree of x)

    Output

    For each query (x, k), output the index of the node whose label is the k-th largest in the subtree of the node x.

    Example

    Input:
    5
    1 3 5 2 7
    1 2
    2 3
    1 4
    3 5
    4
    2 3
    4 1
    3 2
    3 2
    
    Output:
    5
    4
    5
    5
    【分析】给你一棵树以及每个节点的权值,求某个节点以及往下子孙中第K大的节点是哪个。
    先DFS给每个节点编号,然后对于每个节点记录他的开始编号和结束编号,然后就是划分树模板了。
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <time.h>
    #include <string>
    #include <map>
    #include <stack>
    #include <vector>
    #include <set>
    #include <queue>
    #define met(a,b) memset(a,b,sizeof a)
    #define pb push_back
    #define lson(x) ((x<<1))
    #define rson(x) ((x<<1)+1)
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    const int M=1e6+10;
    int le[N],re[N],lab[N],sorted[N];
    int n,m,k,num=0;
    map<int,int>mp;
    struct Edge {
        int to,next;
    } edg[N*2];
    int head[N],tot;
    void init() {
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v) {
        edg[tot].to = v;
        edg[tot].next = head[u];
        head[u] = tot++;
    }
    void dfs(int u,int fa) {
        le[u]=++num;
        sorted[num]=lab[u];
        for(int i=head[u]; i!=-1; i=edg[i].next) {
            int v=edg[i].to;
            if(v!=fa) {
                dfs(v,u);
            }
        }
        re[u]=num;
    }
    int tree[20][N];
    int toleft[20][N];
    void build(int l,int r,int dep) {
        if(l==r)return;
        int mid=(l+r)>>1;
        int same=mid-l+1;
        for(int i=l; i<=r; i++)
            if(tree[dep][i]<sorted[mid])
                same--;
        int lpos=l;
        int rpos=mid+1;
        for(int i=l; i<=r; i++) {
            if(tree[dep][i]<sorted[mid]) { //去左边
                tree[dep+1][lpos++]=tree[dep][i];
            } else if(tree[dep][i]==sorted[mid]&&same>0) { //去左边
                tree[dep+1][lpos++]=tree[dep][i];
                same--;
            } else //去右边
                tree[dep+1][rpos++]=tree[dep][i];
            toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数
        }
        build(l,mid,dep+1);//递归建树
        build(mid+1,r,dep+1);
    }
    void initBuild() {
        for(int i=0; i<20; i++)tree[i][0]=toleft[i][0]=0;
        for(int i=1; i<=n; i++) {
            tree[0][i]=sorted[i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);
    }
    
    int query(int L,int R,int l,int r,int dep,int k) {
        if(l==r)return tree[dep][l];
        int mid=(L+R)>>1;
        int cnt=toleft[dep][r]-toleft[dep][l-1];
        if(cnt>=k) {
            //L+查询区间前去左边的数的个数
            int newl=L+toleft[dep][l-1]-toleft[dep][L-1];
            //左端点+查询区间会分入左边的数的个数
            int newr=newl+cnt-1;
            return query(L,mid,newl,newr,dep+1,k);//注意
        } else {
            //r+区间后分入左边的数的个数
            int newr=r+toleft[dep][R]-toleft[dep][r];
            //右端点减去区间分入右边的数的个数
            int newl=newr-(r-l-cnt);
            return query(mid+1,R,newl,newr,dep+1,k-cnt);//注意
        }
    }
    int main() {
        int u,v,x;
        init();
        scanf("%d",&n);
        for(int i=1; i<=n; i++){
            scanf("%d",&lab[i]);
            mp[lab[i]]=i;
        }
        for(int i=1; i<n; i++) {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs(1,0);
        initBuild();
        scanf("%d",&m);
        while(m--){
            scanf("%d%d",&x,&k);
            u=le[x];v=re[x];
            int ans=query(1,n,u,v,0,k);
            printf("%d
    ",mp[ans]);
        }
        return 0;
    }

  • 相关阅读:
    IdentityServer4 令牌端点
    IdentityServer4 授权端点
    IdentityServer4 发现端点
    IdentityServer4 注销端点
    IdentityServer4 自检端点
    spring boot 项目简单打包部署
    如何进阶成公司 Git 小能手
    Git常用命令参考手册
    网络面试题总结
    Nginx面试可能问到的部分
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/6429425.html
Copyright © 2011-2022 走看看