POJ 3321 树状数组

来源:互联网 发布:电脑记事提醒软件 编辑:程序博客网 时间:2024/05/07 19:59

题意:给定一棵树,某些节点上有苹果,多次询问各子树上的节点数,并且在询问的中途随时可能新增和删除苹果。

分析:dfs遍历树的同时,对每个点标注时间,每个点有一个开始时间和一个结束时间,把这两个时间当做下标,该点的苹果个数(1或0)填入数组的两个对应位。子树中结点的时间段一定是根节点时间段的子段,所以求子树苹果数,只需求数组某区间的和即可。用树状数组比较快。

#include<cstdio>#include<cstring>const int n_max=200005;int n,a[n_max],ne,N;int head[n_max],cnt;int apple[n_max],pos[n_max];struct Node{int v,last;}e[n_max];struct Root{int begin,end;}p[n_max];void addedge(int x,int y){e[ne].v=y;e[ne].last=head[x];head[x]=ne;ne++;}void bfs(int num){p[num].begin=cnt;int i;for(i=head[num];i!=-1;i=e[i].last){bfs(e[i].v);}pos[num]=cnt;p[num].end=cnt++;}void insert(int k,int p){while(k<=N){a[k]+=p;k+=k&(-k);}}int sum(int k){int ret=0;while(k>0){ret+=a[k];k-=k&(-k);}return ret;}int main(){while(~scanf("%d",&n)){ne=0;memset(head,-1,sizeof(head));int i,x,y;for(i=1;i<n;i++){scanf("%d%d",&x,&y);addedge(x,y);}cnt=2;N=n+1;bfs(1);for(i=1;i<=n;i++){apple[i]=1;insert(pos[i],1);}int m,t;char op[10];scanf("%d",&m);while(m--){scanf("%s%d",op,&t);if(op[0]=='Q'){printf("%d\n",sum(p[t].end)-sum(p[t].begin-1));}else{int temp;if(apple[t]==1){temp=-1;}else{temp=1;}insert(pos[t],temp);apple[t]+=temp;}}}return 0;}


原创粉丝点击