http://codeforces.com/problemset/problem/877/E
给出一颗有根树,没个节点上有一个值0/1,有两种操作,一个是选中一个节点,对他所对应的那个子树上所有节点的值进行翻转0->1,1->0,
第二种操作是询问一个节点对应的子树中所有节点的值的和。
如果是对一个区间进行上述操作,那么显然就是裸的线段树了,把这颗树按照先序遍历进行重新编号,这样的优点在于,每个节点对应的子树的节点的编号都是从根开始连续增长的,我们只要知道根的编号和树的大小,就能把上述询问转化为了区间修改查询的线段树了!
思路很棒,可惜自己没想到。
1 #include<iostream> 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define LL long long 5 #define mid ((L+R)>>1) 6 #define lc (id<<1) 7 #define rc (id<<1|1) 8 const int maxn=200010; 9 vector<int>g[maxn]; 10 int p[maxn],son[maxn]; 11 void dfs(int u,int fa,int &x){ 12 p[u]=x; 13 son[p[u]]=1; 14 for(int i=0;i<g[u].size();++i){ 15 if(g[u][i]==fa)continue; 16 dfs(g[u][i],u,++x); 17 son[p[u]]+=son[p[g[u][i]]]; 18 } 19 } 20 int t[maxn],sum[maxn<<2]; 21 bool tag[maxn<<2]; 22 void build(int id,int L,int R){ 23 //puts("FFF"); 24 if(L==R){ 25 sum[id]=t[L]; 26 return; 27 } 28 build(lc,L,mid); 29 build(rc,mid+1,R); 30 sum[id]=sum[lc]+sum[rc]; 31 } 32 void pushdown(int id,int L,int R){ 33 if(tag[id]){ 34 tag[lc]^=1;sum[lc]=(mid-L+1-sum[lc]); 35 tag[rc]^=1;sum[rc]=(R-mid-sum[rc]); 36 tag[id]=0; 37 } 38 } 39 int ask(int id,int L,int R,int l,int r){ 40 if(L>=l&&R<=r){ 41 return sum[id]; 42 } 43 pushdown(id,L,R); 44 if(r<=mid)return ask(lc,L,mid,l,r); 45 else if(l>mid) return ask(rc,mid+1,R,l,r); 46 else return ask(lc,L,mid,l,r)+ask(rc,mid+1,R,l,r); 47 } 48 void change(int id,int L,int R,int l,int r){ 49 if(L>=l&&R<=r){ 50 tag[id]^=1; 51 sum[id]=(R-L+1-sum[id]); 52 return; 53 } 54 pushdown(id,L,R); 55 if(l<=mid) change(lc,L,mid,l,r); 56 if(r>mid) change(rc,mid+1,R,l,r); 57 sum[id]=sum[lc]+sum[rc]; 58 } 59 int main(){ 60 int n,m,v,x=1; 61 scanf("%d",&n); 62 for(int i=2;i<=n;++i){ 63 scanf("%d",&v); 64 g[v].push_back(i); 65 g[i].push_back(v); 66 } 67 dfs(1,0,x); 68 for(int i=1;i<=n;++i){ 69 scanf("%d",&t[p[i]]); 70 } 71 build(1,1,n); 72 scanf("%d",&m); 73 char s[5]; 74 while(m--){ 75 scanf("%s %d",s,&v); 76 if(s[0]=='g'){ 77 printf("%d\n",ask(1,1,n,p[v],p[v]+son[p[v]]-1)); 78 } 79 else{ 80 change(1,1,n,p[v],p[v]+son[p[v]]-1); 81 } 82 } 83 return 0; 84 }