题目
给定一棵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的所有点中出现了多少种本质不同的颜色。请写一个程序,快速回答这些询问。
思路
本质与HDU3333Turing Tree是一样的,方法是可持久化线段树合并。
每个点开一个线段树,保存当前子树下每个深度的颜色数。
再开一棵线段树,保存当前子树下每个颜色最浅的深度。
在进行线段树合并时要注意当两棵树中存在相同颜色时,取较浅的一个,把深的颜色删去,代码比较难调。
需要注意的是,每次删除的操作都要新加节点,不能直接在原来的点上改,需要可持久化的思想。
代码
#include<bits/stdc++.h>
#define M 100005
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
int T,n,m,A[M],h[M],tot,dep[M],inf;
struct edge{
int nxt,to;
}G[M<<1];
void Add(int a,int b){
G[++tot]=(edge){h[a],b};
h[a]=tot;
}
int Lson[M*180],Rson[M*180],cnt[M*180],ver[M],tt;
void Insert1(int &p,int x,int d,int L,int R){
cnt[++tt]=cnt[p];Lson[tt]=Lson[p];Rson[tt]=Rson[p];p=tt;
cnt[p]+=d;
if(L==R)return;
int mid=(L+R)>>1;
if(x<=mid)Insert1(Lson[p],x,d,L,mid);
else Insert1(Rson[p],x,d,mid+1,R);
}
void merge1(int& x,int y,int L,int R){
if(!x||!y){x=(x|y);return;}
cnt[++tt]=cnt[x];Lson[tt]=Lson[x];Rson[tt]=Rson[x];x=tt;
if(L==R){cnt[x]+=cnt[y];return;}
int mid=(L+R)>>1;
merge1(Lson[x],Lson[y],L,mid);
merge1(Rson[x],Rson[y],mid+1,R);
cnt[x]=cnt[Lson[x]]+cnt[Rson[x]];
}
int query(int l,int r,int p,int L,int R){
// cout<<l<<' '<<r<<' '<<p<<' '<<L<<' '<<R<<endl;
if(!p)return 0;
if(l==L&&r==R)return cnt[p];
int mid=(L+R)>>1;
if(r<=mid)return query(l,r,Lson[p],L,mid);
else if(l>mid)return query(l,r,Rson[p],mid+1,R);
return query(l,mid,Lson[p],L,mid)+query(mid+1,r,Rson[p],mid+1,R);
}
int lson[M*25],rson[M*25],dp[M*25],rt[M],ttt;
void Insert2(int &p,int x,int d,int L,int R){
if(!p)p=++ttt,lson[p]=rson[p]=0,dp[p]=1e9;
if(L==R){dp[p]=min(dp[p],d);return;}
int mid=(L+R)>>1;
if(x<=mid)Insert2(lson[p],x,d,L,mid);
else Insert2(rson[p],x,d,mid+1,R);
}
void merge2(int &x,int y,int L,int R,int& p){
if(!x||!y){x=(x|y);return;}
if(L==R){
Insert1(p,max(dp[x],dp[y]),-1,1,n);
dp[x]=min(dp[x],dp[y]);
return;
}
int mid=(L+R)>>1;
merge2(lson[x],lson[y],L,mid,p);
merge2(rson[x],rson[y],mid+1,R,p);
}
int last=0;
int main(){
cin>>T;
while(T--){
clr(h,0);tot=ttt=tt=last=0;
clr(rt,0);clr(ver,0);cnt[0]=0;dp[0]=1e9;Lson[0]=Rson[0]=lson[0]=rson[0]=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
dep[1]=1;
for(int i=2,f;i<=n;i++)scanf("%d",&f),Add(f,i),dep[i]=dep[f]+1;
for(int i=n;i>=1;i--){
Insert1(ver[i],dep[i],1,1,n);
Insert2(rt[i],A[i],dep[i],1,n);
for(int j=h[i];j;j=G[j].nxt){
int u=G[j].to;
merge1(ver[i],ver[u],1,n);
merge2(rt[i],rt[u],1,n,ver[i]);
}
}
for(int i=1,x,d;i<=m;i++){
scanf("%d%d",&x,&d);
x=x^last;d=d^last;
printf("%d\n",last=query(dep[x],min(n,dep[x]+d),ver[x],1,n));
}
}
return 0;
}