题目

给定一棵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;
}