先考虑没有深度限制的情况。
先将每个节点的权值设为1,对于颜色相同且在dfs序中最近的2个点,用倍增求出lca并将它的权值减一。然后子树中不同的颜色种数就是子树的权值和了。
有深度限制时,考虑以深度为时间建立主席树。
将每个点按深度排序,枚举一遍。对每种颜色开一个set,枚举到一个点时将它在dfs序中的位置加入set中并更新就可以了。
时间复杂度O(T*(nlogn+mlogn))
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; if(p1==p2){ p2=(p1=buf)+fread(buf,1,100000,stdin); if(p1==p2)return EOF; } return *p1++; } inline void Read(int& x){ char c=nc(); for(;c<'0'||c>'9';c=nc()); for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc()); } #define N 100010 #define M 20 #define I set<Node3>::iterator struct Node1{ int w,l,r; }a[N*M<<2]; struct Edge{ int t,nx; }e[N]; int x,y,Num,i,j,k,n,T,Cnt,m,d[N],Rt[N],l[N],r[N],h[N],c[N],f[N][M],Last; struct Node3{ int f,w; Node3(){} Node3(int f,int w):f(f),w(w){} bool operator < (Node3 x)const{return w<x.w;} }A[N],Tmp; set<Node3>s[N]; inline int _Min(int x,int y){return x<y?x:y;} inline void Add(int x,int y){e[++Num].t=y;e[Num].nx=h[x];h[x]=Num;} inline void Dfs(int x){ d[x]=d[f[x][0]]+1;l[x]=++Num; for(int i=h[x];i;i=e[i].nx)Dfs(e[i].t); r[x]=Num; } inline void Build(int& Node,int l,int r){ Node=++Cnt;a[Node].w=0; if(l==r)return; int Mid=l+r>>1; Build(a[Node].l,l,Mid); Build(a[Node].r,Mid+1,r); } inline void Insert(int L,int& Node,int x,int l,int r,int y){ Node=++Cnt;a[Node]=a[L]; a[Node].w+=y; if(l==r)return; int Mid=l+r>>1; if(x<=Mid)Insert(a[L].l,a[Node].l,x,l,Mid,y);else Insert(a[L].r,a[Node].r,x,Mid+1,r,y); } inline int Query(int Node,int l,int r,int L,int R){ if(Node==0||l>R||r<L)return 0; if(l>=L&&r<=R)return a[Node].w; int Mid=l+r>>1; return Query(a[Node].l,l,Mid,L,R)+Query(a[Node].r,Mid+1,r,L,R); } inline int Lca(int x,int y){ if(d[x]<d[y])swap(x,y); for(int i=M-1;i>=0;i--) if(d[f[x][i]]>=d[y])x=f[x][i]; if(x==y)return x; for(int i=M-1;i>=0;i--) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } int main() { Read(T); while(T--){ Read(n);Read(m); for(i=1;i<=n;i++)Read(c[i]);memset(h,0,sizeof(h)); for(Num=Cnt=0,i=2;i<=n;i++)Read(f[i][0]),Add(f[i][0],i); for(j=1;j<M;j++) for(i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; Num=0;Dfs(1); for(i=1;i<=n;i++)A[i].f=i,A[i].w=d[i]; sort(A+1,A+n+1); for(i=1;i<=n;i++)s[i].clear(); Build(Rt[1],1,Num);Insert(Rt[1],Rt[1],l[1],1,Num,1);s[c[1]].insert(Node3(1,l[1])); for(i=2;i<=n;i++){ x=A[i-1].f;y=A[i].f; Insert(Rt[d[x]],Rt[d[y]],l[y],1,Num,1); if(s[c[y]].empty())s[c[y]].insert(Node3(y,l[y]));else{ s[c[y]].insert(Node3(y,l[y])); I z=s[c[y]].find(Node3(y,l[y])); I P=--z;z=s[c[y]].find(Node3(y,l[y]));I S=++z; if(P!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(P->f,y)],1,Num,-1); if(S!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(S->f,y)],1,Num,-1); if(P!=s[c[y]].end()&&S!=s[c[y]].end())Insert(Rt[d[y]],Rt[d[y]],l[Lca(P->f,S->f)],1,Num,1); } } Last=0; while(m--){ Read(x);Read(y);x^=Last;y^=Last; Last=Query(Rt[_Min(d[x]+y,A[n].w)],1,Num,l[x],r[x]); printf("%d\n",Last); } } return 0; }