题目描述:
苹果树上有N个节点,苹果只能长在节点上,一个节点要么有一个苹果要么没有。给出树的结构,一种操作是将某个节点的苹果栽下或长出苹果;另一种操作是询问某个节点为根的子树总共有多少苹果。
分析:
题目变形很厉害,不过任然可以用树状数组来解决。
我们将节点重新编号,使得所有孩子节点的编号都小于父亲节点的编号,那么当询问子树总共有多少苹果时就是询问比该节点编号小的节点有多少苹果。也就是树状数组的模型了。
编号规则:照后续遍历的方式给节点编号,得到的编号一定是子树中最大的max,并且记录下该节点之下的最小编号min。那么转换为树状数组模型后,询问节点v时,则回答Sum(v.max)-Sum(v.min-1)。
当然,此题也可以编号之后用线段树来解决。
- /*
- PKU3321 Apple Tree
- */
- #include <stdio.h>
- #include <memory.h>
- #include <malloc.h>
- #define clr(a) memset(a,0,sizeof(a))
- #define N 100005
- typedef struct LinkNode{
- int id;
- struct LinkNode* next;
- }Link;
- typedef struct{
- int index;
- int min;
- }Index;
- //vars
- Link mem[N*2];
- int pmem;
- int n,m;
- Link* a[N];
- int e[N];
- Index idx[N];
- int nidx;
- int b[N];
- int c[N];
- void addNode(int i,int j){
- Link *p = &mem[pmem++];
- p->id=j;
- p->next=a[i];
- a[i]=p;
- }
- void Traversal(int v){
- Link *p;
- e[v]=1;
- idx[v].min=nidx;
- p=a[v];
- while(p!=NULL){
- if(!e[p->id]){
- Traversal(p->id);
- }
- p=p->next;
- }
- idx[v].index=nidx++;
- }
- int lowbit(int x){
- return -x&x;
- }
- void Add(int i,int t){
- while(i<=n){
- c[i]+=t;
- i+=lowbit(i);
- }
- }
- int Sum(int i){
- int s=0;
- while(i>0){
- s+=c[i];
- i-=lowbit(i);
- }
- return s;
- }
- int main()
- {
- while(scanf("%d",&n)!=EOF){
- int i,j,k;
- //input
- clr(a); pmem=0;
- for(k=0;k<n-1;k++){
- scanf("%d%d",&i,&j);
- addNode(i,j);
- addNode(j,i);
- }
- //search tree
- clr(e);
- nidx=1;
- Traversal(1);
- //init tree
- for(k=1;k<=n;k++){
- b[k]=1;
- Add(k,1);
- }
- //work
- char ch[5];
- int sum;
- scanf("%d",&m);
- while(m--){
- scanf("%s%d",ch,&k);
- i=idx[k].index;
- j=idx[k].min;
- if(ch[0]=='C'){ //change
- b[i]=!b[i];
- Add(i,b[i]?1:-1);
- }
- if(ch[0]=='Q'){ //inquiry
- sum=Sum(i)-Sum(j-1);
- printf("%d/n",sum);
- }
- }
- }
- return 0;
- }