poj-3321(dfs+树状数组)
http://acm.hust.edu.cn:8080/judge/problem/viewProblem.action?id=10486
思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,最后搜回来后的深度dep,为这个节点管辖区间的下限high[i],如下图所示。接下来就是树状数组部分了。
[]中的第一个数,为树中这个点映射到线性数组中的所在位置。例如[1,5]中的1代表着映射之后,树的第一个结点在数组中也是第一个位置;
#include<iostream> using namespace std; #define max 100005 struct { int u,v,next; }t[max]; int low[max],high[max],c[max],n,first[max],h; int lowbit(int x) { return x&(-x); } void updata(int i,int j) { while(i<=n) { c[i]+=j; i+=lowbit(i); } } int getsum(int x) { int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } void dfs(int u) //将树形结构映射成线性结构 { low[u]=++h; for(int i=first[u];i!=-1;i=t[i].next) //first这个数组用来判断循环是否结束,当==-1则结束 { dfs(t[i].v); //要是first数组!=-1,说明此处树有子节点,那么需要转换;i=t[i].next结点之后 } //(first结点的值==u或者-1的)所以要历遍玩first结点(t[i].u结点)后,还要历遍 high[u]=h; //t[i].u后面的t[i].v结点 } int main() { while(scanf("%d",&n)>0) { memset(first,-1,sizeof(first)); memset(c,0,sizeof(c)); int i,k=0; for(i=0;i<n-1;i++) //建树 { int u,v; scanf("%d%d",&u,&v); k++; t[k].u=u; t[k].v=v; t[k].next=first[u]; //让这一个结点连在下一个结点之后 first[u]=k; //在dfs中,方便转换 } for(i=1;i<=n;i++) //初始值全部为1 updata(i,1); h=0; dfs(1); int m; scanf("%d",&m); while(m--) { char s[5]; int tmp; scanf("%s%d",s,&tmp); if(s[0]=='Q') { printf("%d\n",getsum(high[tmp])-getsum(low[tmp]-1)); } else { int ans=getsum(low[tmp])-getsum(low[tmp]-1); //在思路里面已经说了,low[tmp]代表的是树的第tmp个结点 if(ans==0) ans=1; else ans=-1; updata(low[tmp],ans); } } } return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。