这个题很有趣,有一点数据结构和图论综合的感觉。
题目大意为:给出一个树(非二叉树),节点数从1编号至n。初始时每个节点都有一个苹果。现在有两种操作:
1.Q x,询问以x为根节点的子树的苹果个数的总合;
2.C x,改变x节点的值,若原来为1,则改为0;若原来为0,则改为1。
首先如何得到某个节点的子树的所有节点?可以前序遍历这课树,这样所有的儿子在遍历时的顺序一定是连续的。
在进入儿子们,先记录此时的序号,即根节点的序号;遍历完儿子们之后,再记录此时的序号,就得到了儿子们遍历顺序的起始和终结。
再把每个节点映射到他们被遍历的顺序,维护一个BIT即可。
还有一个纠结的地方就是存图。原先是直接用vector,t了,于是换了手写的edge结构体。
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <vector> using namespace std; #define MAXN 100010 #define lowbit(x) (x & -x) template <class T> inline int RD(T &x) { x = 0; char ch = getchar(); while(!isdigit(ch)) { ch = getchar(); if(ch == EOF) return 0; } while(isdigit(ch)) { x *= 10; x += ch - '0'; ch = getchar(); } return 1; } int son[MAXN][2], a[MAXN], pre[MAXN]; int n, m, u, v, k, x, tot; char op[4]; struct Edge { int v, pre; Edge() {} Edge(int _v, int _pre): v(_v), pre(_pre) {} }ee[MAXN]; void add_edge(int u, int v) { ee[tot] = Edge(v, pre[u]); pre[u] = tot++; } void dfs(int rt) { son[rt][0] = k++; for(int i = pre[rt]; i; i = ee[i].pre) dfs(ee[i].v); son[rt][1] = k - 1; } int sum(int i) { int ret = 0; while(i > 0) ret += a[i], i -= lowbit(i); return ret; } void add(int i, int v) { while(i <= n) a[i] += v, i += lowbit(i); } int main() { // freopen("E.in", "r", stdin); RD(n); for(int i = 1; i <= n; i++) add(i, 1); tot = 1; memset(pre, 0, sizeof(pre)); for(int i = 1; i < n; i++) { RD(u), RD(v); add_edge(u, v); } k = 1; dfs(1); RD(m); while(m--) { op[0] = getchar(); RD(x); if(op[0] == 'Q') printf("%d\n", sum(son[x][1]) - sum(son[x][0] - 1)); if(op[0] == 'C') { int tmp = sum(son[x][0]) - sum(son[x][0] - 1); tmp = tmp > 0 ? -1 : 1; add(son[x][0], tmp); } } return 0; }