树状数组+DFS
1. 题意:有一颗苹果树,每个每个节点都能长1个苹果,初始时,苹果是满的,每次可能读取的事件,
a) 询问在某个节点为根的子树的苹果总
b) 摘取某节点的苹果
c) 在某个某个节点长出苹果
2. 首先自己写的时候想直接用父子关系来更新每个节点的苹果,结果超时了,后来看了题解才知道还能转化为树状数组,原来树状数组的使用也是很灵活的
3. 首先的话就是把原来树上的父子关系转化为一个可以用树状数组来处理得关系,又因为刚好深度遍历在同一子树上的所有节点都是连在一起的,所以就可以先求出节点的(前序遍历)深度遍历顺序,而后面再求某个子树的和就等于右节点的sum-左节点的sum
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define N 100010
using namespace std;
struct Edge
{
int next;
int v;
}g[N*2];
struct Node
{
int l,r;
bool apple;
}tree[N];
int head[N];
int n,coun,m,top;
int c[N];
int index[N];
int lowbit(int x){return x&(-x);}
void addedge(int x,int y)
{
g[coun].next=head[x];
g[coun].v=y;
head[x]=coun++;
g[coun].next=head[y];
g[coun].v=x;
head[y]=coun++;
}
void DFS(int pos,int last)
{
int ret=1;
tree[pos].l=top++;
index[pos]=top;
for(int p=head[pos];p;p=g[p].next)
{
if(g[p].v != last)
{
DFS(g[p].v,pos);
}
}
tree[pos].r=top;
tree[pos].apple=true;
}
void insert(int p,int x)
{
for(int i=p;i<=n;i+=lowbit(i))
{
c[i]+=x;
}
}
int getsum(int p)
{
int ret=0;
for(int i=p;i>0;i-=lowbit(i))
{
ret+=c[i];
}
return ret;
}
int main()
{
//freopen("input.txt","r",stdin);
memset(head,0,sizeof(head));
scanf("%d",&n);
int X,Y;
char ch;
coun=1;
for(int i=1;i<n;++i)
{
scanf("%d%d",&X,&Y);
addedge(X,Y);
}
top=0;
DFS(1,0);
//init sum array
memset(c,0,sizeof(c));
for(int i=1;i<=n;++i)
{
insert(i,1);
}
scanf("%d",&m);
for(int i=0;i<m;++i)
{
scanf(" %c %d",&ch,&X);
if(ch == 'Q')
{
printf("%d\n",getsum(tree[X].r)-getsum(tree[X].l));
}
else
{
if(tree[X].apple)
{
insert(index[X],-1);
}
else
{
insert(index[X],1);
}
tree[X].apple=!tree[X].apple;
}
}
return 0;
}