给出一个苹果树,是一棵树,在每个节点出有一个苹果,然后根节点标号总为1,给出一棵树,上来都有苹果
然后给出一些节点上的操作,操作是进行相反状态有和没有苹果的改变,给出一些询问操作,就是某个节点的子树上所有苹果,包括自己
这题说实话,今天下午耗时最大理解时间最长的题了。。。。
首先用邻接表存储这棵树,然后由于这棵树的节点标号是任意的,所以想到用dfs遍历树一遍后按照访问的次序给树标号,当然也能够求出
某个节点当前的号low[x],和最后一颗字数节点的号high[x],得出一个区间,这个区间上的苹果数就是x节点和子树的苹果数
然后就对一个苹果的新标号进行update这题就解决了。。。。。
有个小问题就是如何判断当前是否有苹果?当前苹果数就 =get(low[x])-get(low[x]-1),还有个办法就是用个标记数组flag来记录每一次的访问,访问一次状态更改一次
#include <stdio.h> #include <string.h> #define MAX 100010 struct node { int data; node* next; }; struct adj { node *first; }list[MAX]; int low[MAX],high[MAX],cnt,c[MAX]; bool visit[MAX]; void dfs(int x) { node *l=list[x].first; cnt++; low[x]=cnt; while(l!=NULL) { dfs(l->data); l=l->next; } high[x]=cnt; //printf("i=%d: l=%d h=%d\n",x,low[x],high[x]); } int lowbit(int x) { return x&(-x); } void update(int x,int flag) { while(x<MAX) { c[x]+=flag; x+=lowbit(x); } } int get(int x) { int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } void init() { cnt=0; memset(c,0,sizeof(c)); for(int i=1;i<MAX;i++) { list[i].first=NULL; visit[i]=true; } } int main() { int n,m,num,u,v; node *tmp; char q[3]; while(scanf("%d",&n)!=EOF) { init(); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); tmp=new node; tmp->data=v; tmp->next=list[u].first; list[u].first=tmp; } dfs(1); for(int i=1;i<MAX;i++) update(i,1); scanf("%d",&m); while(m--) { scanf("%s%d",q,&num); //printf("get(%d)=%d get(%d)=%d\n",high[num],get(high[num]),low[num]-1,get(low[num]-1)); if('Q'==q[0]) printf("%d\n",get(high[num])-get(low[num]-1)); else { if(get(low[num])-get(low[num]-1)==0)//计算出当前是否有苹果 update(low[num],1); else update(low[num],-1); /* if(visit[num])//这里可用一个标记来判断当前苹果状态,访问一次变一次 update(low[num],-1); else update(low[num],1); visit[num]^=1;*/ } } } }