POJ 1321 Apple Tree【树状数组】
题意: 有一棵有 n 个节点并以 1 为根节点的树, 一开始每个节点有 1 个苹果,定义两种操作
Q i 询问以 i 为根节点的树上有多少个苹果。
C i 如果i 这个节点上有 1 个苹果就把它摘下,否在就在这个节点装上一个苹果。
分析: 可以把树上的每个节点对应到树状数组中, 对应的时候,越靠近根节点的节点管辖的数组区间范围越大, 可以利用深搜,根据访问的时间戳的顺序,依次为每个节点标记
在树状数组中的下限 l[i], 因为要使得越靠近叶子节点的节点管辖区间越小,可以利用深搜回溯的特点,即越靠近叶子的节点,回溯到本身的时间差越短,这个时间差即为
该节点覆盖的数组区间长度,因此每个节点覆盖的数组上限 h[i] = l[i] + 访问该节点与回溯到该节点的时间差
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) int n; int a[100005]; int lowbit(int x) { return (x)&(-x); } void add(int pos,int x) { while(pos<=n) { a[pos]+=x; pos+=lowbit(pos); } } int sum(int pos) { if(pos==0) return 0; int sum=0; while(pos>0) { sum+=a[pos]; pos-=lowbit(pos); } return sum; } int l[100005]; int h[100005]; struct node { int to,next; }e[100005]; int tot; int head[100005]; void addedge(int s,int u) { e[tot].to=u; e[tot].next=head[s]; head[s]=tot++; } int t1,t2; void dfs(int r) { l[r]=t1++; int i,k; for(i=head[r];i;i=e[i].next) { k=e[i].to; dfs(k); } h[r]=t1-1; } int num[100005]; int main() { char s[2]; int i,m,f,son,p; while(scanf("%d",&n)!=EOF) { clr(a); clr(head); tot=1; t1=1; for(i=1;i<=n;i++) { add(i,1); num[i]=1; } for(i=0;i<n-1;i++) { scanf("%d%d",&f,&son); addedge(f,son); } dfs(1); scanf("%d",&m); while(m--) { scanf("%s%d",s,&p); if(*s=='Q') printf("%d\n",sum(h[p])-sum(l[p]-1)); else { if(num[p]) { num[p]=0; add(l[p],-1); } else { num[p]=1; add(l[p],1); } } } } return 0; }