ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节
点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离
,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。
每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色
。请写一个程序,快速回答这些询问。

Input

第一行包含一个正整数T(1<=T<=500),表示测试数据的组数。
每组数据中,第一行包含两个正整数n(1<=n<=100000)和m(1<=m<=100000),表示节点数和询问数。
第二行包含n个正整数,其中第i个数为c[i](1<=c[i]<=n),分别表示每个节点的颜色。
第三行包含n-1个正整数,其中第i个数为f[i+1](1<=f[i]<i),表示节点i+1的父亲节点的编号。
接下来m行,每行两个整数x(1<=x<=n)和d(0<=d<n),依次表示每个询问。
输入数据经过了加密,对于每个询问,如果你读入了x和d,那么真实的x和d分别是x xor last和d xor last,
其中last表示这组数据中上一次询问的答案,如果这是当前数据的第一组询问,那么last=0。
输入数据保证n和m的总和不超过500000。

Output

对于每个询问输出一行一个整数,即答案。

用线段树合并预处理出每个点为根的子树中有哪些颜色以及每种颜色的最浅深度

其中记录最浅深度的权值线段树需要可持久化以便在线回答询问

合并颜色线段树时若发现颜色重复,则对应删去深度线段树中这种颜色较大的一个深度

时间复杂度O((n+m)logn)

#include<cstdio>
#include<cstring>
#define G *++ptr
char buf[20000000],*ptr=buf-1;
int _(){
    int x=0,c=G;
    while(c<48)c=G;
    while(c>47)x=x*10+c-48,c=G;
    return x;
}
const int N=100007;
int n,m,col[N],dep[N],rt_del;
int es[N],enx[N],e0[N],ep=2;
int rt1[N],ch1[N*20][2],p1=0,dep1[N*20];
int rt2[N],ch2[N*80][2],p2=0,sz[N*80];
int max(int a,int b){return a>b?a:b;}
void mins(int&a,int b){if(a>b)a=b;}
int ins1(int x,int y){
    int u=++p1,u0=u;
    for(int i=16;~i;--i)u=ch1[u][x>>i&1]=++p1;
    dep1[u]=y;
    return u0;
}
int ins2(int x,int a){
    int u=++p2,u0=u;
    for(int i=16;~i;--i)sz[u=ch2[u][x>>i&1]=++p2]=a;
    return u0;
}
int mg2(int a,int b){
    if(!a||!b)return a|b;
    int c=++p2;
    if(ch2[a][0]||ch2[a][1]){
        ch2[c][0]=mg2(ch2[a][0],ch2[b][0]);
        ch2[c][1]=mg2(ch2[a][1],ch2[b][1]);
        sz[c]=sz[ch2[c][0]]+sz[ch2[c][1]];
    }else{
        sz[c]=sz[a]+sz[b];
    }
    return c;
}
int mg1(int a,int b){
    if(!a||!b)return a|b;
    if(ch1[a][0]||ch1[a][1]){
        ch1[a][0]=mg1(ch1[a][0],ch1[b][0]);
        ch1[a][1]=mg1(ch1[a][1],ch1[b][1]);
    }else{
        rt_del=mg2(rt_del,ins2(max(dep1[a],dep1[b]),-1));
        mins(dep1[a],dep1[b]);
    }
    return a;
}
int lss2(int w,int x){
    ++x;
    int s=0;
    for(int i=16,d;~i;--i){
        d=x>>i&1;
        if(d)s+=sz[ch2[w][0]];
        w=ch2[w][d];
    }
    return s;
}
void f1(int w){
    rt1[w]=ins1(col[w],dep[w]);
    rt2[w]=ins2(dep[w],1);
    for(int i=e0[w],u;i;i=enx[i]){
        u=es[i];
        dep[u]=dep[w]+1;
        f1(u);
    }
    rt_del=0;
    for(int i=e0[w],u;i;i=enx[i]){
        u=es[i];
        rt1[w]=mg1(rt1[w],rt1[u]);
        rt2[w]=mg2(rt2[w],rt2[u]);
    }
    rt2[w]=mg2(rt2[w],rt_del);
}
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    for(int T=_();T;--T){
        n=_();m=_();
        for(int i=1;i<=n;++i)col[i]=_();
        for(int i=2,f;i<=n;++i){
            f=_();
            es[ep]=i;enx[ep]=e0[f];e0[f]=ep++;
        }
        f1(1);
        for(int i=1,x,d,la=0;i<=m;++i){
            x=_()^la;d=_()^la;
            printf("%d\n",la=lss2(rt2[x],d+dep[x]));
        }
        ep=2;
        memset(e0,0,sizeof(int)*(n+2));
        memset(ch1,0,sizeof(ch1[0])*(p1+1));
        memset(dep1,0,sizeof(int)*(p1+1));
        memset(ch2,0,sizeof(ch2[0])*(p2+1));
        memset(sz,0,sizeof(int)*(p2+1));
        p1=p2=0;
    }
    return 0;
}

 

posted on 2017-03-18 16:30  nul  阅读(1054)  评论(0编辑  收藏  举报