题意:
有一棵树,这棵树上有很多果子,一开始每个果子都在,给出下面两种操作:
1.C x,改变果子x的状态,如果有,那么久摘下来;没有,就变为有;
2.Q x,问在x上面的(包括x)有多少个果子。
思路:
多叉树,朴素的更新方法就是从叶子到根的路径上的点的值全部更新,但是这样每更新的复杂度是O(n)。
所以就要考虑如何较快地更新。
树状数组的更新是logn,那么就要考虑如何把树上的问题转换为区间的问题,这就用到了dfs序。
“一棵子树的dfs序就变成了一个区间”
通过记录dfs序,那么一个节点及其子节点就构成了一段连续的区间,所以就可以用树状数组进行信息的维护。
对于这道题来说,对于每一个节点,记录两个信息,一个是第一次访问到它的时间l,第二个是它的子节点中最大的访问时间r,那么从l到r这一段连续的数字就是这个节点及其所有子节点的区间。
更新x,就是将l[x] ~ n这一段区间更新;
查询x上面的数字之和,就是查询1 ~ r[x] 与 1 ~ l[x]-1的差值。
这两个操作就是树状数组的基本功能,单点更新与区间查询。
注意建树不能用vector,得用链式前向星。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 2e5 + 10; 6 struct edge 7 { 8 int to,next; 9 } edges[N]; 10 int head[N]; 11 int l[N],r[N]; 12 int c[N]; 13 bool vis[N]; 14 int tot = 0,n; 15 int cnt; 16 void adde(int u,int v) 17 { 18 edges[++cnt].to = v; 19 edges[cnt].next = head[u]; 20 head[u] = cnt; 21 } 22 void dfs(int u,int fa) 23 { 24 l[u] = ++tot; 25 for (int i = head[u];i;i = edges[i].next) 26 { 27 int v = edges[i].to; 28 if (v != fa) 29 { 30 dfs(v,u); 31 } 32 } 33 r[u] = tot; 34 } 35 int lowbit(int x) 36 { 37 return x&(-x); 38 } 39 void add(int x,int y) 40 { 41 for (int i = x;i <= n;i += lowbit(i)) c[i] += y; 42 } 43 int getsum(int x) 44 { 45 int ans = 0; 46 for (int i = x;i > 0;i -= lowbit(i)) ans += c[i]; 47 return ans; 48 } 49 int main() 50 { 51 int m; 52 while (scanf("%d",&n) != EOF) 53 { 54 tot = 0; 55 cnt = 0; 56 memset(l,0,sizeof(l)); 57 memset(r,0,sizeof(r)); 58 memset(c,0,sizeof(c)); 59 memset(head,0,sizeof(head)); 60 for (int i = 1;i <= n;i++) 61 { 62 vis[i] = 1; 63 } 64 //for (int i = 1;i <= n;i++) g[i].clear(); 65 for (int i = 0;i < n - 1;i++) 66 { 67 int u,v; 68 scanf("%d%d",&u,&v); 69 adde(u,v); 70 adde(v,u); 71 } 72 dfs(1,-1); 73 //printf("%d %d ",l[3],r[3]); 74 for (int i = 1;i <= n;i++) add(i,1); 75 scanf("%d",&m); 76 for (int i = 0;i < m;i++) 77 { 78 char s[5]; 79 scanf("%s",s); 80 if (s[0] == 'Q') 81 { 82 int x; 83 scanf("%d",&x); 84 int mx = getsum(r[x]); 85 int mi = getsum(l[x] - 1); 86 //printf("%d %d** ",r[x],l[x]); 87 printf("%d ",mx - mi); 88 } 89 else 90 { 91 int x; 92 scanf("%d",&x); 93 if (vis[x]) 94 { 95 vis[x] = 0; 96 add(l[x],-1); 97 } 98 else 99 { 100 vis[x] = 1; 101 add(l[x],1); 102 } 103 } 104 } 105 } 106 return 0; 107 }