题目大意:
有一颗苹果树,里面有n个节点,由n-1条边连接,形成一个树状关系,每一个节点有一个苹果,输入会将某个节点的苹果摘取或者添加,问单个节点及其子节点总共的苹果个数。
思路:
非常王道的思路,dfs序加上树状数组,这里就要说一下dfs序,顾名思义加上深度搜索的搜索路径记录成一个序列,其目的就是为了管理每一个节点的子节点,具体的情况可以看下图
相信深搜你会了吧(如果不会就去重修数据结构),其实按照这个结果我们就可以看出些东西了。每一个节点都会出现两次,两次的中间所包括的都是其子节点,这样我们使用树状数组和线段树的时候就可以更好的遍历空间。对于一棵树的dfs序而言,同一棵子树所对应的一定是dfs序中连续的一段,具体还是看代码吧。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int max1=1e5+1;
vector<vector<int> > dp(max1);
int begin[max1],end[max1],tree[max1],c[max1];
int n,m,time;
void dfs(int k)
{
time++;
begin[k]=time;//保存其dfs序的开始
for(int i=0;i<dp[k].size();i++)
{
dfs(dp[k][i]);
}
end[k]=time;//保存其dfs序的结束
}
//数状数组的模板 PS:和我的模板有一些不一样,这是比较简化版本
int lowbit(int x)
{
return x & -x;
}
void add(int x,int k)
{
while(x<=n)
{
tree[x]+=k;
x+=lowbit(x);
}
}
int look(int x)
{
int ans=0;
while(x>0)
{
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
time=0;
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d %d",&a,&b);
dp[a].push_back(b);//保存每一个节点的子节点
}
dfs(1);//dfs得出dfs序
for(int i=1;i<=n;i++)
{
add(i,1);//树状数组设初值
c[i]=1;//判断节点是否有苹果
}
scanf("%d",&m);
while(m--)
{
int t;
char q[12];
scanf("%s%d",q,&t);
if(q[0]=='Q'){
printf("%d\n",look(end[t])-look(begin[t]-1));//从dfs序的结尾减去开头正好是中间我们所需要的值
}else{//拿走与添加苹果
if(c[t]){
add(begin[t],-1);c[t]=0;
}else{
add(begin[t],1);c[t]=1;
}
}
}
}
return 0;
}