POJ 3321 Apple Tree DFS序+fenwick

题目大意:有一颗长满苹果的苹果树,有两个操作。

1.询问以一个点为根的子树中有多少个苹果。

2.看看一个点有没有苹果,如果没有苹果,那么那里就马上长出一个苹果(= =!);否则就把那个苹果摘下来。


思路:进行一次深搜,将每个节点最开始出现的时间和最后出现的时间记在一个数组里,那么这两点之间的点就是它以及它的子树的二倍,然后就用树状数组来维护区间和就行了。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
using namespace std;

pair<int,int> pos[MAX];

int points,asks;
int head[MAX],total;
int next[MAX << 1],aim[MAX << 1];
int cnt;
bool src[MAX];
int fenwick[MAX];

char c[10];

inline void Add(int x,int y);
void DFS(int x,int last);

inline void Fix(int x,int c);
inline int GetSum(int x);

int main()
{
	cin >> points;
	for(int x,y,i = 1;i < points; ++i) {
		scanf("%d%d",&x,&y);
		Add(x,y),Add(y,x);
	}
	DFS(1,-1);
	memset(src,true,sizeof(src));
	for(int i = 1;i <= points; ++i)
		Fix(pos[i].first,1),Fix(pos[i].second,1);
	cin >> asks;
	for(int x,i = 1;i <= asks; ++i) {
		scanf("%s%d",c,&x);
		if(c[0] == 'Q')
			printf("%d\n",(GetSum(pos[x].second) - GetSum(pos[x].first - 1)) >> 1);
		else {
			if(src[x]) {
				Fix(pos[x].first,-1);
				Fix(pos[x].second,-1);
				src[x] = false;
			}
			else {
				Fix(pos[x].first,1);
				Fix(pos[x].second,1);
				src[x] = true;
			}
		}
	}
	return 0;
}

inline void Add(int x,int y)
{
	next[++total] = head[x];
	aim[total] = y;
	head[x] = total;
}

void DFS(int x,int last)
{
	pos[x].first = ++cnt;
	for(int i = head[x];i;i = next[i]) {
		if(aim[i] == last)	continue;
		DFS(aim[i],x);
	}
	pos[x].second = ++cnt;
}

inline void Fix(int x,int c)
{
	for(;x <= (points << 1);x += x&-x)
		fenwick[x] += c;
}

inline int GetSum(int x)
{
	int re = 0;
	for(;x;x -= x&-x)
		re += fenwick[x];
	return re;
}


你可能感兴趣的:(poj,树状数组,dfs序,fenwick)