Apple Tree
-
描述
-
There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree.
The tree has N forks which are connected by branches. Kaka numbers the forks by 1 to N and the root is always numbered by 1. Apples will grow on the forks and two apple won't grow on the same fork. kaka wants to know how many apples are there in a sub-tree, for his study of the produce ability of the apple tree.
The trouble is that a new apple may grow on an empty fork some time and kaka may pick an apple from the tree for his dessert. Can you help kaka?
-
输入
-
The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.
The following N - 1 lines each contain two integers u and v, which means fork u and fork v are connected by a branch.
The next line contains an integer M (M ≤ 100,000).
The following M lines each contain a message which is either
"C x" which means the existence of the apple on fork x has been changed. i.e. if there is an apple on the fork, then Kaka pick it; otherwise a new apple has grown on the empty fork.
or
"Q x" which means an inquiry for the number of apples in the sub-tree above the fork x, including the apple (if exists) on the fork x
Note the tree is full of apples at the beginning
输出
- For every inquiry, output the correspond answer per line. 样例输入
-
3 1 2 1 3 3 Q 1 C 2 Q 1
样例输出
-
3 2
题目大意:一棵苹果树(不一定是二叉树),每个节点有一个苹果, kaka的一次操作C可以摘一个节点的苹果或者使没有苹果的节点长出苹果, 查询的是某棵子树上的苹果总数。
思路:
明显的区间求和问题,可以用线段树和树状数组求解。 问题的关键在于把树存储在一维数组中,这个用一个深搜可以解决, 用三个数组data存每个点(重新排序的点)的数据, start[i] 表示原始节点i在data 里的位置, end[i] 表示原始节点i子树在data里的结束点, 所以求子树i的总苹果数就是start[i]到end[i]在data中所有数据的和。区间查询就是线段树或树状数组的基本操作了。
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct Node { int child; Node *next; }Node; Node node[100001]; int n, m, top = 0, data[100001], start[100001], end[100001]; void dfs(int pos) { start[pos] = ++top; //为所有节点重新编号, 并确定start,end数组的值 Node *p = node[pos].next; while(p) { if(start[p->child] == 0) { dfs(p->child); } p = p->next; } end[pos] = top; } int lowbit(int x) //树状数组求点到区间临界距离的函数 { return x & (-x); } int getsum(int end) //树状数组区间求和 { int sum = 0; while(end > 0) { sum += data[end]; end -= lowbit(end); } return sum; } void change(int pos, int item) //树状数组更改节点的值 { while(pos <= n) { data[pos] += item; pos += lowbit(pos); } } int main() { int i, k, s, e, temp; char c; scanf("%d", &n); for(i = 1; i < n; i++) //建立树 { scanf("%d%d", &s, &e); Node *p = (Node *)malloc(sizeof(Node)); p->child = e; p->next = node[s].next; node[s].next = p; } dfs(1); //初始化那三个数组 for(i = 1; i <= n; i++) { change(i, 1); } scanf("%d", &m); for(i = 0; i < m; i++) //查询 { getchar(); scanf("%c%d", &c, &k); if(c == 'C') { temp = getsum(start[k]); temp -= getsum(start[k]-1); if(temp) { change(start[k], -1); } else { change(start[k], 1); } } else { temp = getsum(end[k]); temp -= getsum(start[k]-1); printf("%d\n", temp); } } return 0; }
-
The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.