树状数组
题意:给定一棵树,某些节点上有苹果,多次询问各子树上的节点数,并且在询问的中途随时可能新增和删除苹果。
分析:dfs遍历树的同时,对每个点标注时间,每个点有一个开始时间和一个结束时间,把这两个时间当做下标,该点的苹果个数(1或0)填入数组的两个对应位。子树中结点的时间段一定是根节点时间段的子段,所以求子树苹果数,只需求数组某区间的和即可。用树状数组比较快。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; #define maxn 200005 struct sedge { int v, next; }edge[maxn]; struct sfork { int s, e; }fork[maxn]; int edgenum, head[maxn], xtime, ar[maxn * 2], apple[maxn], N; void addedge(int a, int b) { edge[edgenum].v = b; edge[edgenum].next = head[a]; head[a] = edgenum; edgenum++; } void dfs(int a) { fork[a].s = xtime; xtime++; for (int i = head[a]; i != -1; i = edge[i].next) dfs(edge[i].v); fork[a].e = xtime; xtime++; } int lowbit(int t) { return t &(-t); } void add(int i, int v) { for (; i < N; ar[i] += v, i += lowbit(i)); } int sum(int i) { int s = 0; for (; i > 0; s += ar[i], i-=lowbit(i)); return s; } int main() { //freopen("D:\\t.txt", "r", stdin); edgenum = 0; xtime = 1; memset(head, -1, sizeof(head)); int n; scanf("%d", &n); for (int i = 0; i < n - 1; i++) { int a, b; scanf("%d%d", &a, &b); addedge(a, b); } dfs(1); memset(ar, 0, sizeof(ar)); N = n * 2; for (int i = 1; i <= N; i++) ar[i] = (i) - (i - lowbit(i)); for (int i = 1; i <= n; i++) apple[i] = 1; int q; scanf("%d", &q); getchar(); for (int i = 0; i < q; i++) { char ch; int num; scanf("%c%d", &ch, &num); getchar(); if (ch == 'C') { int temp; if (apple[num] == 1) temp = -1; else temp = 1; add(fork[num].s, temp); add(fork[num].e, temp); apple[num] += temp; } else printf("%d\n", (sum(fork[num].e) - sum(fork[num].s))/2 + apple[num]); } return 0; }