Description:
给出一个树包含n个节点,每个节点的值可以为0或者1,初始时每个节点的值都为1,现在给出m个询问,cmd为Q时输出x及其子树的值之和,cmd为C时将节点x的值异或1.
Input :
n,m,以及m各询问.
Output:
按次序依次输出.
Analysis:
这一题一看大概就是用数据结构了,首先就是不能每次都找子树的节点,要先记录每个点的子树下的节点有哪些。可是即使能做到记录每个节点的子树都包含哪些节点,每操作一遍的话都是要O(n)的,这样的境遇让人想起了区间求和问题也是如此,即使一个一个加一个一个查询,每次操作也要O(n)的样子,这样也让人想起单点修改区间求和的树状数组了。
至于,怎样记录每个节点的子树下有哪些点,并且把他们形成一个区间,可以dfs一遍,用时间戳记录每个节点的开始和结束时间,这样,开始和结束时间在star[u]和end[u]之间的点恰好就是u节点的所有子节点形成的区间。这样就可以将节点映射到新的适于树状数组的区间了,求和时由于对称性将结果除以二即可,这样就做到了O(logn)的查询和修改
(P.S. 用vector<int>G[maxn]超时,而用vector<vector<int> >G 通过了。说明至少对于一组数据来说,后者会更快一些)
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<time.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 0xffffff0;
const int MOD = 1e9 + 7;
const int maxn = 100005;
int n;
int C[maxn * 2], a[maxn];
vector<vector<int> > G;
int Tcount;
int idx[maxn][2];
void add(int x, int num) {
while (x <= 2*n) {
C[x] += num;
x += x & (-x);
}
}
int sum(int x) {
int ans = 0;
while (x>0) {
ans += C[x];
x -= x & (-x);
}
return ans;
}
int vis[maxn*2];
void dfs(int u, int fa) {
idx[u][0] = ++Tcount;
vis[u] = 1;
for (int i = 0; i<G[u].size(); ++i) {
int v = G[u][i];
if (v != fa&&!vis[v]) {
dfs(v,u);
}
}
idx[u][1] = ++Tcount;
}
int main() {
freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
scanf("%d", &n);
G.resize(n + 1);
//_rep(i, 1, n)G[i].clear();
_for(i, 0, n-1) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
Tcount = 0;
memset(vis, 0, sizeof(vis));
dfs(1, 0);
for (int i = 1; i <= n * 2; ++i)C[i]=i-(i-(i&(-i)));
for (int i = 0; i <= n; ++i)a[i] = 1;
int Q; scanf("%d", &Q);
char cmd[2];
int x;
while (Q--) {
scanf("%s%d", cmd, &x);
if (cmd[0] == 'Q') {
printf("%d\n", (sum(idx[x][1]) - sum(idx[x][0] - 1)) / 2);
}
else {
a[x] ^= 1;
if (a[x]) add(idx[x][1], 1), add(idx[x][0], 1);
else add(idx[x][1], -1), add(idx[x][0], -1);
}
}
return 0;
}