http://poj.org/problem?id=3321
题目大意:
给你N个点组成的树 每个点初始化为1 有两种操作
C x:改变点的值 是1变0 是0变1
Q x:问以x为根的子树上点值的和
思路:
主要是把树映射到树状数组中
一遍dfs把点重新编号 low和high low表示刚搜到此点时的计数,high是搜玩其子树内所有节点后回来的计数编号
比如说又n个点那么根节点1的low=1,high=2*n
这样就映射到树状数组中啦。
代码及其注释:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<queue> #include<algorithm> #include<stack> using namespace std; const int N=100010; struct node { struct tt *next; }mem[N]; struct tt { struct tt *next; int j; }; int n,I;//n is the number of apples I 是全局计数 int c[N*2]; int high[N]; int low[N]; bool visited[N]; int apple[N];//某个点是否有苹果 void build(int i,int j)//建树 { struct tt *t=new tt; t->j=j; t->next=mem[i].next; mem[i].next=t; } void dele()//一定的清理 { for(int i=1;i<=n;++i) mem[i].next=NULL; } int lowbit(int x) { return x&(-x); } void Add(int x,int k) { for(int i=x;i<=2*n;i+=lowbit(i)) { c[i]+=k; } } int Sum(int x) { int sum=0; for(int i=x;i>0;i-=lowbit(i)) { sum+=c[i]; } return sum; } void dfs(int x)//深搜 计数 { visited[x]=true; ++I; low[x]=I; struct tt *t=new tt; t=mem[x].next; while(t!=NULL) { if(visited[t->j]==false) { dfs(t->j); } t=t->next; } ++I; high[x]=I; } int main() { int m; while(scanf("%d",&n)!=EOF) { memset(c,0,sizeof(c)); for(int i=1;i<n;++i) { int l,r; scanf("%d %d",&l,&r); build(l,r); build(r,l); } I=0; memset(visited,false,sizeof(visited)); dfs(1); for(int i=1;i<=n;++i) { apple[i]=1; } for(int i=1;i<=2*n;++i) { Add(i,1);//初始化树状数组 } scanf("%d",&m); while(m--) { char c; int k; getchar(); scanf("%c %d",&c,&k); if(c=='Q') { printf("%d\n",(Sum(high[k])-Sum(low[k]-1))/2); }else { if(apple[k]==1) { apple[k]=0; Add(low[k],-1); Add(high[k],-1); } else { apple[k]=1; Add(low[k],1); Add(high[k],1); } } } dele(); } return 0; }