zoukankan      html  css  js  c++  java
  • SPOJ Query on a tree III (树剖(dfs序)+主席树 || Splay等平衡树)(询问点)

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

    Define the query (xk): 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 uv. 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 xk. (k <= the total node number in the subtree of x)

    Output

    For each query (xk), 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

    求x子树中第k大的节点。

     题意:

    一个以1为root的树,每次询问以x为根的子树里第k大的节点是哪个。

    思路:

    首先声明一下,因为是查询子树,而不是路径,这里只用到了树剖的dfs序部分,top等是没有用到的。即是这道题不需要树剖,这里写树剖这是练习!此外尝试把模板打好,方便以后参考。

    • 注意,这里的第k大是指从小到大排序的第k(不是第一次遇到这样的题了,可能是我数学不好)。
    • 题目中的“no two nodes have the same labels”应该是查询的子树里面不会出现相同的,而整棵树里面是有的(这里WA了(2^n)!次)。但是有多个的话,map又是这么映射成功的。。。。?
    • 刚刚在学树剖,于是想到了树剖,因为size[x]记录了x的子树在对应的数据结构(这里是主席树)中的左右边界。由于没有修改操作,所以可以用主席树,不然用Splay等平衡树也是可以的。这样,结合主席树对x的子树进行查询:pos=query(rt[tid[x]-1],rt[tid[x]+sz[x]-1],1,n,k)
    • 主席树的数组要开大一点。
    • 注意主席树的每一个数组和树剖的数组不要搞混了。
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<map>
    using namespace std;
    map<int,int>mp;
    const int maxn=200010;
    int Laxt[maxn],Next[maxn],To[maxn];
    int n,N,a[maxn],b[maxn],c[maxn];//a是原数组,b是排序数组,c是位置数组.
    inline void read(int &res)
    {
        char chr;res=0;do chr=getchar();while(chr<'0'||chr>'9');
        while(chr<='9'&&chr>='0') res=(res<<3)+(res<<1)+chr-'0',chr=getchar();
    }
    struct Treecut_PIT
    {
        int sz[maxn],son[maxn],fa[maxn],dpt[maxn],cnt;
        int tid[maxn],Rank[maxn],top[maxn],tim;
        int rt[maxn*10],sum[maxn*10],ch[maxn*10][2],tot;//主席树部分 
        void init()
        {
            mp.clear();
            cnt=1;tim=0;tot=0;//cnt对边,tim对应树剖时间,tot对应主席树 
            memset(Laxt,0,sizeof(Laxt));
            memset(son,0,sizeof(son));
            memset(tid,0,sizeof(tid));
        }
        void add_edge(int u,int v)
        {
            Next[++cnt]=Laxt[u];
            Laxt[u]=cnt;
            To[cnt]=v;
        }
        void dfs1(int u,int pre)
        {
            fa[u]=pre;dpt[u]=dpt[pre]+1;sz[u]=1;
            for(int i=Laxt[u];i;i=Next[i]){
                int v=To[i]; if(v==pre) continue;
                dfs1(v,u); sz[u]+=sz[v];
                if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
            }
        }
        void dfs2(int u,int Top)
        {
            tid[u]=++tim; Rank[tim]=u; top[u]=Top; 
            if(!son[u]) return ;
            dfs2(son[u],Top);
            for(int i=Laxt[u];i;i=Next[i])
            {
                int v=To[i];
                if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
             }
        }
        void Build(int &Now,int L,int R)
        {
            Now=++tot;sum[tot]=0;
            if(L==R)  return;
            int Mid=(L+R)>>1;
            Build(ch[Now][0],L,Mid);
            Build(ch[Now][1],Mid+1,R);
        }
        void insert(int &Now,int last,int L,int R,int pos)
        {
            Now=++tot;
            ch[Now][0]=ch[last][0];
            ch[Now][1]=ch[last][1];
            sum[Now]=sum[last]+1;
            if(L==R) return; 
            int Mid=(L+R)>>1;
            if(pos<=Mid) insert(ch[Now][0],ch[last][0],L,Mid,pos);
            else insert(ch[Now][1],ch[last][1],Mid+1,R,pos);
        }
        void Make_tree()
        {
    
            for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[a[i]]=i;
            for(int i=1;i<n;i++) {
                int u,v; read(u);read(v);
                add_edge(u,v); add_edge(v,u);
            }
            dfs1(1,0); dfs2(1,1);     
            for(int i=1;i<=n;i++) b[i]=a[Rank[i]]; 
            sort(b+1,b+n+1);N=unique(b+1,b+n+1)-(b+1);    //注意是对线段树的顺序来离散。 
            for(int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+N+1,a[Rank[i]])-b;//离散化 Build(rt[0],1,n);
            Build(rt[0],1,N);
            for(int i=1;i<=n;i++) insert(rt[i],rt[i-1],1,N,c[i]);
        }
        int query(int ss,int tt,int L,int R,int k)
        {
             if(L==R) return L;
             int Mid=(L+R)>>1, tmp=sum[ch[tt][0]]-sum[ch[ss][0]];
             if(k<=tmp) return query(ch[ss][0],ch[tt][0],L,Mid,k);
             else return query(ch[ss][1],ch[tt][1],Mid+1,R,k-tmp);
        }
        void Query()
        {
            int q,x,k;  scanf("%d",&q);
            while(q--){
                read(x);read(k);
                int pos=query(rt[tid[x]-1],rt[tid[x]+sz[x]-1],1,n,k);
                printf("%d
    ",mp[b[pos]]);
             }
        }
    }Tc;
    int main()
    {
        while(~scanf("%d",&n)){
            Tc.init();
            Tc.Make_tree();
            Tc.Query();
        } return 0;
    }
  • 相关阅读:
    SilverLight使用WCF RIA SERVICE实现对数据库的操作 (添加,删除,更新)
    c# 创建、读取、添加、修改xml文件
    Winform 下载文件进度条设计
    WOrd ,excel实现打印功能
    码云与Git的使用
    while循环和字符串格式化
    python环境搭建
    python简介与简单入门
    整型与布尔的转换、字符串的切片和几个常用的方法
    python2与python3的区别
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8060062.html
Copyright © 2011-2022 走看看