题意:一棵树上有n个叉子(其实就是n个节点),再告诉你n-1个线段告诉你是u和v节点相连的,再输入m组操作,有两种操作,当是Q操作时你就要输出对象的节点上有多少个苹果(初始化时每个节点都有苹果),C操作是吃掉苹果或是长出苹果(一个节点只能是有一个苹果或是没有苹果,即:有苹果就是吃掉当前节点的苹果,没苹果就是长出苹果)。
思路:可以把它倒过来就可以用树状数组做了,就是还要用dfs来搜一下每个节点的分支有多少个,开始的时间和结束的时间就可以了。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=100005;
struct node1
{
int next;
int tail;
}edge[maxn]; //这结构体是表示第i条边的下一条边的编号和这条边所连的节点
struct node2
{
int l,r;
}apple[maxn]; //苹果树表示i节点的开始时间个终止时间
int s[maxn],cnt,c[maxn],a[maxn]; //s存储的是i节点的分支数,cnt是总共的节点数,c数组是树状数组,a是树状数组的每个节点的权值(1或是0)
void dfs(int u)
{
int i;
apple[u].l=cnt;
for(i=s[u];i!=-1;i=edge[i].next)
dfs(edge[i].tail);
apple[u].r=cnt++;
}
int lowbit(int x)
{
return x&(-x);
}
void change(int x)
{
int i;
if(a[x])
for(i=x;i<cnt;i+=lowbit(i))
c[i]++;
else
for(i=x;i<cnt;i+=lowbit(i))
c[i]--;
}
int sum(int x)
{
int res=0;
while(x)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
int main()
{
int n,m,t1,t2,t;
char str[5];
scanf("%d",&n);
memset(s,-1,sizeof(s));
memset(apple,0,sizeof(apple));
memset(c,0,sizeof(c));
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&t1,&t2);
edge[i].tail=t2;
edge[i].next=s[t1];
s[t1]=i;
}
cnt=1;
dfs(1);
scanf("%d",&m);
for(int i=1;i<=n;i++) //初始化每个节点的权值都是1
{
a[i]=1;
change(i);
}
while(m--)
{
scanf("%s%d",&str,&t);
if(str[0]=='Q')
printf("%d\n",sum(apple[t].r)-sum(apple[t].l-1));
else
{
a[apple[t].r]=(a[apple[t].r]+1)%2; //权值只能是0和1 所以对2取余
change(apple[t].r);
}
}
return 0;
}