Poj 3321 Apple Tree(树变序列+时间戳+树状数组)

来源:互联网 发布:alt 左键 ubuntu 编辑:程序博客网 时间:2024/06/05 22:56

题目链接:http://poj.org/problem?id=3321

题意:一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。

思路:用DFS时间戳的方法将树转变为序列:做一次dfs,记下每个节点的开始时间Start[i]和结束时间End[i],那么对于i节点的所有子孙的开始时间和结束时间都应位于Start[i]和End[i]之间。以start[]值作为点新的标号,state[]数组表示当前位置的状态(是否有苹果),构建树状数组。

注意:因为DFS过程对每个点标号两次,所以相关数组需要两倍大。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N= 100000*2+5;int bit[N],start[N],end[N];bool visit[N],state[N];int time;struct Node{int x,next;Node () {}Node (int _x,int _n)  {x=_x;next=_n;}  }edges[N];int head[N];int e=0;inline void Add (int u, int v){edges[e] = Node (v,head[u]);head[u] = e++;}void Init (){e=0;time=0;   //时间戳memset(start,0,sizeof(start));memset(end,0,sizeof(e));memset(head,-1,sizeof(head));memset(visit,false,sizeof(visit));memset(bit,0,sizeof(bit));}inline int lowbit (int x){return x&(-x);}void Update (int k,int x){while(k<=time){bit[k]+=x;k+=lowbit(k);}}int Getsum (int k){int sum=0;while (k>0){sum+=bit[k];k-=lowbit(k);}return sum;}void DFS (int x) //时间戳 树转序列{visit[x]=true;time++;start[x]=time;for (int i=head[x];i!=-1;i=edges[i].next)if (visit[edges[i].x]==false)DFS(edges[i].x);time++;end[x]=time;}int main (){int n,u,v,i;while (~scanf("%d",&n)){Init ();for (i=1;i<=n-1;i++)  //n-1条边{scanf("%d%d",&u,&v);Add(u,v);Add(v,u);}DFS (1);for (i=1;i<=n;i++)  //初始都为1state[i]=true,Update (start[i],1);int q,x;char str[10];scanf("%d",&q);  while (q--){scanf("%s%d",str,&x);if (str[0]=='C')if (state[x])state[x]=false,Update(start[x],-1);elsestate[x]=true,Update(start[x],1);elseprintf("%d\n",Getsum(end[x])-Getsum(start[x]-1));}}return 0;}


原创粉丝点击