ZOJ 3686 A Simple Tree Problem 线段树
如果把一颗树跑一遍拓扑排序,会发现每颗子树都在一个区间里。
那么对子树的操作就变成对区间的操作。
#include<stdio.h> #include<vector> #include<iostream> #include<string.h> #include<stdlib.h> using namespace std; const int MAXN=100100; int n,m; int t; int id[MAXN]; int num[MAXN]; vector<int> g[MAXN]; int calnum(int u) { int x=1; for(int i=0;i<g[u].size();i++) x+=calnum(g[u][i]); return num[u]=x; } int topo(int u) { for(int i=0;i<g[u].size();i++) topo(g[u][i]); id[u]=t--; return 0; } int sum[MAXN<<2]; int flag[MAXN<<2]; int build() { memset(sum,0,sizeof(sum)); memset(flag,0,sizeof(flag)); } int PushDown(int idx,int l,int r) { if(flag[idx]) { int mid=(r+l)>>1; flag[idx<<1]^=1; sum[idx<<1]=mid-l+1-sum[idx<<1]; flag[idx<<1|1]^=1; sum[idx<<1|1]=r-mid-sum[idx<<1|1]; flag[idx]=0; } return 0; } int update(int idx,int l,int r,int tl,int tr) { if(tl<=l&&tr>=r) { flag[idx]^=1; sum[idx]=r-l+1-sum[idx]; return 0; } PushDown(idx,l,r); int mid=(r+l)>>1; if(tl<=mid)update(idx<<1,l,mid,tl,tr); if(tr>mid)update(idx<<1|1,mid+1,r,tl,tr); sum[idx]=sum[idx<<1]+sum[idx<<1|1]; return 0; } int query(int idx,int l,int r,int tl,int tr) { if(tl<=l&&tr>=r) return sum[idx]; PushDown(idx,l,r); int mid=(r+l)>>1; int x=0; if(tl<=mid) x+=query(idx<<1,l,mid,tl,tr); if(tr>mid) x+=query(idx<<1|1,mid+1,r,tl,tr); return x; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) g[i].clear(); for(int i=2;i<=n;i++) { int x; scanf("%d",&x); g[x].push_back(i); } calnum(1); t=n; topo(1); build(); for(int i=1;i<=m;i++) { char op[10]; int u; scanf("%s%d",op,&u); if(op[0]=='o') update(1,1,n,id[u],id[u]+num[u]-1); else { int x=query(1,1,n,id[u],id[u]+num[u]-1); printf("%d\n",x); } } printf("\n"); } return 0; }