【题解】
我们可以发现每次修改之后叶子结点到根的路径最多分为两段:一段白色或者黑色,上面接另一段灰色的。二分+倍增找到分界点,然后更新答案即可。
check的时候只需要判断当前节点对应的叶子结点的区间是否全部为同一种颜色,用树状数组维护所有叶子节点组成的序列的状态即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<cmath> 6 #define LL long long 7 #define rg register 8 #define N 200010 9 using namespace std; 10 int n,m,rt,cnt,ans0,ans1,l[N],r[N],t[N],col[N],dep[N],pos[N],lea[N],p[N][25]; 11 vector<int>son[N]; 12 inline int read(){ 13 int k=0,f=1; char c=getchar(); 14 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 15 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 16 return k*f; 17 } 18 void dfs(int x){ 19 dep[x]=dep[p[x][0]]+1; 20 if(!son[x].size()){ 21 if(col[x]==1) ans1++;else ans0++; 22 pos[x]=l[x]=r[x]=++cnt; lea[cnt]=x; return; 23 } 24 int cnt0=0,cnt1=0; 25 for(rg int i=0;i<(int)son[x].size();i++){ 26 dfs(son[x][i]); 27 l[x]=min(l[x],l[son[x][i]]); r[x]=max(r[x],r[son[x][i]]); 28 if(!col[son[x][i]]) cnt0++; 29 else if(col[son[x][i]]==1) cnt1++; 30 } 31 if(cnt0==(int)son[x].size()) col[x]=0,ans0++; 32 else if(cnt1==(int)son[x].size()) col[x]=1,ans1++; 33 else col[x]=2; 34 } 35 inline void add(int x,int y){for(;x<=n;x+=x&-x)t[x]+=y;} 36 inline int query(int x){int ret=0;for(;x;x-=x&-x)ret+=t[x];return ret;} 37 int main(){ 38 memset(l,0x7f,sizeof(l)); 39 memset(r,0,sizeof(r)); 40 n=read(); m=read(); 41 for(rg int i=1;i<=n;i++){ 42 son[p[i][0]=read()].push_back(i); 43 if(!p[i][0]) rt=i; 44 } 45 for(rg int i=1;i<=n;i++) col[i]=read(); 46 dfs(rt); 47 // for(rg int i=1;i<=n;i++) printf("[%d %d] ",l[i],r[i]); 48 for(rg int j=1;j<21;j++) 49 for(rg int i=1;i<=n;i++) p[i][j]=p[p[i][j-1]][j-1]; 50 for(rg int i=1;i<=n;i++) add(i,col[lea[i]]); 51 // printf("%d %d %d ",ans1,ans0,n-ans0-ans1); 52 while(m--){ 53 int x=read(),y=x; 54 if(col[x]){ 55 for(rg int i=20;i>=0;i--)if(p[y][i]){ 56 int pa=p[y][i],sum=query(r[pa])-query(l[pa]-1); 57 if(sum==r[pa]-l[pa]+1) y=pa; 58 } 59 ans1-=dep[x]-dep[y]+1; 60 // printf("y=%d ",y); 61 add(pos[x],-1); y=x; 62 for(rg int i=20;i>=0;i--)if(p[y][i]){ 63 int pa=p[y][i],sum=query(r[pa])-query(l[pa]-1); 64 if(sum==0) y=pa; 65 } 66 ans0+=dep[x]-dep[y]+1; 67 // printf("y=%d ",y); 68 } 69 else{ 70 for(rg int i=20;i>=0;i--)if(p[y][i]){ 71 int pa=p[y][i],sum=query(r[pa])-query(l[pa]-1); 72 if(sum==0) y=pa; 73 } 74 ans0-=dep[x]-dep[y]+1; 75 // printf("y=%d ",y); 76 add(pos[x],1); y=x; 77 for(rg int i=20;i>=0;i--)if(p[y][i]){ 78 int pa=p[y][i],sum=query(r[pa])-query(l[pa]-1); 79 if(sum==r[pa]-l[pa]+1) y=pa; 80 } 81 ans1+=dep[x]-dep[y]+1; 82 // printf("y=%d ",y); 83 } 84 col[x]^=1; 85 printf("%d %d %d ",ans1,ans0,n-ans0-ans1); 86 } 87 return 0; 88 }