题意:n个点,n-1条边,有m个查询,Q a,表示a的子树中包含a有多少苹果。C a,表示a这个点如果有苹果就被摘掉,没有苹果就长出一个。
将对应点转换成对应区间,然后进行线段树
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
const int N=1e5+2;
struct Node
{
int l,r;
int sum;
}Tree[N*4];
int from[N],to[N],num,vis[N];
struct Graph
{
int head[N*2],pnt[N*2],next[N*2],tot;
void init()
{
tot=0;
mem(head,-1);
}
void add(int u,int v)
{
pnt[tot]=v;
next[tot]=head[u];
head[u]=tot++;
}
}G;
void dfs(int u)
{
vis[u]=1;
from[u]=num++;
for(int i=G.head[u];i!=-1;i=G.next[i])
{
int v=G.pnt[i];
if(vis[v]) continue;
dfs(v);
}
to[u]=num-1;
}
void Build(int rt,int l,int r)
{
Tree[rt].l=l;
Tree[rt].r=r;
if(l==r) { Tree[rt].sum=1;return ;}
int mid=(r+l)>>1;
Build(rt<<1,l,mid);
Build(rt<<1|1,mid+1,r);
Tree[rt].sum=r-l+1;
}
int Query(int rt,int l,int r)
{
if(Tree[rt].l==l&&Tree[rt].r==r) return Tree[rt].sum;
int mid=(Tree[rt].l+Tree[rt].r)>>1;
if(l>mid) return Query(rt<<1|1,l,r);
else if(r<=mid) return Query(rt<<1,l,r);
else return Query(rt<<1,l,mid)+Query(rt<<1|1,mid+1,r);
}
void Update(int rt,int x)
{
if(Tree[rt].l==x&&Tree[rt].r==x)
{
Tree[rt].sum^=1;
return;
}
int mid=(Tree[rt].l+Tree[rt].r)>>1;
if(x<=mid) Update(rt<<1,x);
else Update(rt<<1|1,x);
Tree[rt].sum=Tree[rt<<1].sum+Tree[rt<<1|1].sum;
}
int main()
{
int n,m,i;
char str[5];
while(~scanf("%d",&n))
{
G.init();
int a,b;
num=1;
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
G.add(a,b); G.add(b,a);
}
mem(vis,0);
dfs(1);
Build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%s%d",str,&a);
if(str[0]=='Q')
{
printf("%d\n",Query(1,from[a],to[a]));
}
else Update(1,from[a]);
}
}
return 0;
}