poj 3321
题意:一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,最后搜回来后的深度dep,为这个节点管辖区间的下限high[i],如下图所示。接下来就是树状数组部分了。
代码:
#include<iostream> #include<fstream> using namespace std; int n,m; struct e{ int data; e *next; }; e edge[100001]; int node[100001]; int v[100001]; int b[100001]; int end[100001]; int sum; void dfs(int s){ int i,j,k; v[s]=++sum; e *p=edge[s].next; while(p){ if(v[p->data]==0) dfs(p->data); p=p->next; } end[s]=sum; } int lowbit(int x){ return x&(-x); } void add(int s,int t){ while(s<=n) { b[s]+=t; s+=lowbit(s); } } int getsum(int s){ int i=0; while(s>0) { i+=b[s]; s-=lowbit(s); } return i; } void read(){ // ifstream cin("in.txt"); int i,j,k,s,t; // cin>>n; scanf("%d",&n); for(i=1;i<n;i++) { // cin>>s>>t; scanf("%d%d",&s,&t); e *p=new e; p->data=t; p->next=edge[s].next; edge[s].next=p; e *q=new e; q->data=s; q->next=edge[t].next; edge[t].next=q; } dfs(1); char c; for(i=1;i<=n;i++) add(i,1); // cin>>m; scanf("%d",&m); for(i=1;i<=m;i++) { // cin>>c>>j; getchar(); scanf("%c%d",&c,&j); if(c=='C') { s=getsum(v[j]); s-=getsum(v[j]-1); if(s==1) add(v[j],-1); else add(v[j],1); } else { s=getsum(end[j]); s-=getsum(v[j]-1); cout<<s<<endl; } } } int main(){ read(); return 0; }