题意:
一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:
(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
参考了:http://www.cnblogs.com/ybrbupt/archive/2011/09/24/2189519.html
思路:
树形数组,但是问题的关键是,如何把树的各个节点映射到数组中去,然后再应用树形数组的优势去解决?
dfs()函数中的代码就十分精妙的体现了如何去映射。相当于把每个节点重新编号了。
初始化要注意,因为开始默认每个节点都会有个苹果,所以先要对c[]数组进行初始化,c[]对应的线性数组每个元素都是1,所以c[i]=i&-i就行了
#include <cstdio> #include <cstdlib> #include <cstring> #include <vector> using namespace std; const int MAXN = 100010; vector<vector<int>> G(MAXN); bool vis[MAXN]; bool apple[MAXN]; int high[MAXN], low[MAXN]; int c[MAXN]; int n, count; inline int lowbit(int x) { return x & (-x); } void dfs(int u) { vis[u] = true; low[u] = count; // 节点u为根节点的子树映射到数组内的下届 for (int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if (!vis[v]) dfs(v); } high[u] = count++; // 节点u为根节点的子树映射到数组内的上界 } int sum(int p) { int ans = 0; for (int i = p; i > 0; i -= lowbit(i)) ans += c[i]; return ans; } inline void update(int p) { int d; if (apple[p]) d = -1; else d = 1; apple[p] ^= true; for (int i = p; i <= n; i += lowbit(i)) c[i] += d; } int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) c[i] = lowbit(i), apple[i] = true, vis[i] = false; for (int i = 1; i < n; ++i) { int a, b; scanf("%d %d", &a, &b); G[a].push_back(b); G[b].push_back(a); } count = 1; dfs(1); int m; scanf("%d", &m); for (int i = 1; i <= m; ++i) { char s[10]; int u; scanf("%s %d", s, &u); if (s[0] == 'Q') printf("%d\n", sum(high[u]) - sum(low[u]-1)); else if (s[0] == 'C') update(high[u]); } return 0; }