POJ-3321 Apple Tree (树状数组 前缀和 dfs序)

Apple Tree
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 31249   Accepted: 9396

Description

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?

POJ-3321 Apple Tree (树状数组 前缀和 dfs序)_第1张图片

Input

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
"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
"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

Output

For every inquiry, output the correspond answer per line.

Sample Input

3
1 2
1 3
3
Q 1
C 2
Q 1

Sample Output

3
2
 
  
#include 
#include 
#include 
using namespace std;
#define maxn 100005
int c[maxn], left[maxn], right[maxn], sz[maxn], tot;
vector<vector > g(maxn);
inline int lowbit(int x){ return x & (-x);}
int getsum(int x){
	int ans = 0;
	while(x){
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}
void add(int x, int n, int v){
	while(x <= n){
		c[x] += v;
		x += lowbit(x);
	}
}
void dfs(int x){
	left[x] = tot;
	for(int i = 0; i < g[x].size(); ++i){
		tot++;
		dfs(g[x][i]);
	}
	right[x] = tot;
}
int main(){
	int n, u, v, q;
	while(scanf("%d", &n) != EOF){
		for(int i = 1; i < n; ++i){
			scanf("%d %d", &u, &v);
			g[u].push_back(v);
		}
		memset(c, 0, sizeof(c));
		for(int i = 1; i <= n; ++i){
			sz[i] = 1;
			add(i, n, 1);
		}
		tot = 1;
		dfs(1);
		char s;
		scanf("%d", &q);
		while(q--){
			getchar();
			s = getchar();
			if(s == 'C'){
				scanf("%d", &u);
				if(sz[u]){
					add(left[u], n, -1);
				}
				else{
					add(left[u], n, 1);
				}
				sz[u] ^= 1;
			}
			else{
				scanf("%d", &u);
				printf("%d\n", getsum(right[u]) - getsum(left[u] - 1));
			}
		}
		for(int i = 0; i <= n; ++i){
			g[i].clear();
		}
	}
}

/*
题意:一颗树有1e5个点,每个点上权值仅可为0或1。1e5次操作,要么修改某个点的权值,要么询问
某结点包括所有其儿子的权值和。

思路:如果不是树型结构,而是线性的,在一个一维区间上,点的值仅为0或1,然后修改点值,询问
区间权值和,这很容易的,用树状数组求个前缀和然后减减就行了。那么这道题就需要先用dfs序把树型
转成"线性"。在dfs的过程中,我们按顺序给访问到的结点标号,那么对于某个结点,它的标号L一定小于
它所有儿子结点的标号,那么我们对每个结点,再记录一个儿子结点标号的最大值R,那么区间[L,R]就表示
该结点以及它所有儿子结点的标号区间了。
这样我们dfs一遍,对结点打个标记,然后对于所有询问和修改操作,就当做线性用树状数组维护就行了。

坑:之前开vectorg[maxn] T了多次,发现vector > g(maxn)快一倍。。。。
*/

你可能感兴趣的:(POJ,dfs序,树状数组,数据结构-树状数组,数据结构-树链剖分)