CF-877E-线段树+哈希

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 }

 

posted @ 2018-11-04 22:09  *zzq  阅读(340)  评论(0编辑  收藏  举报