题目大意为给出一棵树,节点数<=100000,树中的节点可能有苹果,两种操作:一种是改变某一节点的苹果,有改为无,无改为有。第二种操作是求某一节点和以该节点为根的子树的苹果总数。操作数达到了100000;
这题需要把一个树形结构变换为线性结构,然后使用树状数组动态求和。变换方法为DFS一次这棵树,记录下每个节点第一次访问和最后一次访问时的顺序编号,这时,在某节点第一次访问和最后一次访问编号之间的访问编号,必定为该节点的子节点,按照访问编号建立树状数组,当改变某一节点苹果时,只需按照该节点第一次访问的编号在树状数组中修改值,查询时统计某节点在第一次访问和最后一次访问编号之间的和。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
struct Edge
{
int u, v, next;
Edge() {}
Edge(int t_u, int t_v, int t_next) : u(t_u), v(t_v), next(t_next) {}
}edges[2*MAXN];
int head[MAXN], len, dfn, n, m;
int first[MAXN], last[MAXN];
bool visit[MAXN];
int Tree[MAXN], num[MAXN];
void Init()
{
len = dfn = 0;
memset(head, -1, sizeof(head));
memset(visit, false, sizeof(visit));
memset(Tree, 0, sizeof(Tree));
memset(num, 0, sizeof(num));
}
void addEdge(int u, int v)
{
edges[len].u = u;
edges[len].v = v;
edges[len].next = head[u];
head[u] = len++;
edges[len].u = v;
edges[len].v = u;
edges[len].next = head[v];
head[v] = len++;
}
void dfs(int u)
{
visit[u] = true;
first[u] = ++dfn;
for(int i = head[u]; i != -1; i = edges[i].next)
{
int v = edges[i].v;
if(!visit[v])
{
dfs(v);
}
}
last[u] = dfn;
return ;
}
inline int lowbit(int x)
{
return x & (-x);
}
void modify(int x, int val)
{
for(int i = x; i <= n; i += lowbit(i))
{
Tree[i] += val;
}
return ;
}
int getsum(int x)
{
int ret = 0;
for(int i = x; i > 0; i -= lowbit(i))
{
ret += Tree[i];
}
return ret;
}
int main()
{
//freopen("aa.in", "r", stdin);
//freopen("bb.out", "w", stdout);
char ch;
int u, v;
while(scanf("%d", &n) != EOF)
{
Init();
for(int i = 1; i < n; ++i)
{
scanf("%d %d", &u, &v);
addEdge(u, v);
}
dfs(1);
for(int i = 1; i <= n; ++i)
{
modify(first[i], 1);
}
scanf("%d", &m);
while(m--)
{
cin >> ch >> u;
if(ch == 'C')
{
if(num[first[u]] % 2 == 0)
modify(first[u], -1);
else
modify(first[u], 1);
num[first[u]]++;
}
else if(ch == 'Q')
{
int ans = getsum(last[u]);
if(first[u] > 1)
ans -= getsum(first[u]-1);
cout << ans << endl;
}
}
}
return 0;
}