可以用树状数组实现,每次C就是改值,每次Q就是查询。但是由于题目是给的树结构,而树状数组求和是线性区间,所以需要将题目中的树节点编号,并对每个结点划分它的子树区间以便求和。
用dfs后序遍历整棵树标记序号,然后取子树中最小结点为左端点,自身编号是右端点。之后用树状数组就可以了。
用vector会超时,自己写了个数组的邻接表居然AC了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <list>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 100005
#define LEN 555555<<2
using namespace std;
struct Node
{
int L,R,num;
};
int cnt;
int gl[MAXN][105];
Node node[MAXN];
void dfs(int u)
{
for(int i=1; i<=gl[u][0]; ++i)
dfs(gl[u][i]);
node[u].num=++cnt;
}
int set_segment(int u)
{
node[u].L=node[u].R=node[u].num;
for(int i=1; i<=gl[u][0]; ++i)
node[u].L=min(node[u].L,set_segment(gl[u][i]));
return node[u].L;
}
struct BIT
{
int data[MAXN];
int sz;
void init(int n)
{
sz=n;
memset(data,0,sizeof(data));
}
int lowbit(int x)
{
return -x&x;
}
void add(int p,int v)
{
while(p<=sz)
{
data[p]+=v;
p+=lowbit(p);
}
}
int sum(int p)
{
int s=0;
while(p>0)
{
s+=data[p];
p-=lowbit(p);
}
return s;
}
};
BIT tree;
bool vis[MAXN];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
tree.init(n);
memset(gl,0,sizeof(gl));
for(int i=1; i<=n; ++i)
tree.add(i,1);
for(int i=1; i<n; ++i)
{
int x,y;
scanf("%d%d",&x,&y);
int &len=gl[x][0];
gl[x][++len]=y;
}
cnt=0;
dfs(1);
set_segment(1);
int t;
scanf("%d",&t);
char str[5];
memset(vis,1,sizeof(vis));
while(t--)
{
int x;
scanf("%s%d",str,&x);
if(str[0]=='Q')
{
int l=node[x].L,r=node[x].R;
printf("%d\n",tree.sum(r)-tree.sum(l-1));
}
else
{
int num=node[x].num;
if(!vis[x]) tree.add(num,1);
else tree.add(num,-1);
vis[x]=!vis[x];
}
}
}
return 0;
}