版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82184847
传送门:bzoj4771
题解
为满足深度和子树两个限制,预处理出
序和每层的点,然后按深度递增,
序为下标建立主席树,每次询问查询
,
表示
序中
的子树区间。
为保证每个出现的颜色贡献为
,每个颜色建一个按
序升序排列的
,
中每个点贡献
,每两个邻点的
贡献
,每次增加深度更新
时,
_
找到位置,把前驱和后继的
贡献
,再分别把该点和前驱后继的
贡献
即可。
代码
#include<bits/stdc++.h>
#define gc getchar()
#define si isdigit(c)
#define mid (((l)+(r))>>1)
using namespace std;
const int N=1e5+10,M=1e7+10;
int T,n,m,ans,d[N],col[N],in[N],ot[N],dfn,cnt;
int rt[N],ls[M],rs[M],ss[M],mxdep,F[N][19],bin[20];
struct G{
int tot,head[N],to[N],nxt[N];
inline void clr()
{memset(head,0,sizeof(head));tot=0;}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
}A,B;
struct cmp{
bool operator()(const int x,const int y){
return in[x]<in[y];
}
};
set<int,cmp>S[N];
char c;
inline void rd(int &x)
{
c=gc;x=0;
for(;!si;c=gc);
for(;si;c=gc) x=x*10+(c^48);
}
inline void dfs(int x)
{
in[x]=++dfn;B.lk(d[x],x);
int i;
for(i=1;bin[i]<=d[x];++i)
F[x][i]=F[F[x][i-1]][i-1];
for(;i<19;++i) F[x][i]=0;
for(i=A.head[x];i;i=A.nxt[i]){
d[A.to[i]]=d[x]+1;F[A.to[i]][0]=x;dfs(A.to[i]);
}
ot[x]=dfn;
if(in[x]==ot[x]) mxdep=max(d[x],mxdep);
}
inline void pushup(int k)
{ss[k]=ss[ls[k]]+ss[rs[k]];}
inline void ins(int &k,int l,int r,int pos,int val)
{
if(!k){k=++cnt;ls[k]=rs[k]=ss[k]=0;}
if(l==r) {ss[k]+=val;return;}
if(pos<=mid) ins(ls[k],l,mid,pos,val);
else ins(rs[k],mid+1,r,pos,val);
pushup(k);
}
inline int merge(int x,int y,int l,int r)
{
if(!x || !y) return x|y;
if(l==r) {ss[x]+=ss[y];return x;}
ls[x]=merge(ls[x],ls[y],l,mid);
rs[x]=merge(rs[x],rs[y],mid+1,r);
pushup(x);
return x;
}
inline int LCA(int x,int y)
{
if(d[x]<d[y]) swap(x,y);
if(x==y) return x;
int t=d[x]-d[y],i;
for(i=0;bin[i]<=t;++i)
if((t&bin[i])) x=F[x][i];
for(i=18;i>=0 && x!=y;--i)
if(F[x][i]!=F[y][i])
x=F[x][i],y=F[y][i];
return x==y?x:F[x][0];
}
inline int query(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) return ss[k];
int re=0;
if(L<=mid) re=query(ls[k],l,mid,L,R);
if(R>mid) re+=query(rs[k],mid+1,r,L,R);
return re;
}
int main(){
int i,j,x,D,nxt,pre;
bin[0]=1;
for(i=1;i<19;++i) bin[i]=bin[i-1]<<1;
rd(T);
while(T--){
cnt=ans=dfn=0;A.clr();B.clr();
rd(n);rd(m);
for(i=1;i<=n;++i) rd(col[i]),S[i].clear();
for(i=2;i<=n;++i){rd(x);A.lk(x,i);}
d[1]=1;mxdep=0;dfs(1);
rt[0]=0;
for(D=1;D<=mxdep;++D){
rt[D]=0;
for(i=B.head[D];i;i=B.nxt[i]){
j=B.to[i];
ins(rt[D],1,n,in[j],1);
set<int>::iterator ori,orz;
ori=orz=S[col[j]].lower_bound(j);
pre= ori==S[col[j]].begin()?-1:*(--ori);
nxt= orz==S[col[j]].end()?-1:*orz;
if(pre!=-1) ins(rt[D],1,n,in[LCA(pre,j)],-1);
if(nxt!=-1) ins(rt[D],1,n,in[LCA(j,nxt)],-1);
if(pre!=-1 && nxt!=-1) ins(rt[D],1,n,in[LCA(pre,nxt)],1);
S[col[j]].insert(j);
}
rt[D]=merge(rt[D],rt[D-1],1,n);
}
while(m--){
rd(x);rd(D);
x^=ans;D^=ans;
D=min(mxdep,d[x]+D);
printf("%d\n",(ans=query(rt[D],1,n,in[x],ot[x])));
}
}
}