POJ 3321 Apple Tree(树状数组)

Description:

给出一个树包含n个节点,每个节点的值可以为0或者1,初始时每个节点的值都为1,现在给出m个询问,cmd为Q时输出x及其子树的值之和,cmd为C时将节点x的值异或1.

Input :

n,m,以及m各询问.

Output:
按次序依次输出.

Analysis:

这一题一看大概就是用数据结构了,首先就是不能每次都找子树的节点,要先记录每个点的子树下的节点有哪些。可是即使能做到记录每个节点的子树都包含哪些节点,每操作一遍的话都是要O(n)的,这样的境遇让人想起了区间求和问题也是如此,即使一个一个加一个一个查询,每次操作也要O(n)的样子,这样也让人想起单点修改区间求和的树状数组了。

至于,怎样记录每个节点的子树下有哪些点,并且把他们形成一个区间,可以dfs一遍,用时间戳记录每个节点的开始和结束时间,这样,开始和结束时间在star[u]和end[u]之间的点恰好就是u节点的所有子节点形成的区间。这样就可以将节点映射到新的适于树状数组的区间了,求和时由于对称性将结果除以二即可,这样就做到了O(logn)的查询和修改

(P.S. 用vector<int>G[maxn]超时,而用vector<vector<int> >G 通过了。说明至少对于一组数据来说,后者会更快一些)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<time.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 0xffffff0;
const int MOD = 1e9 + 7;
const int maxn = 100005;

int n;
int C[maxn * 2], a[maxn];
vector<vector<int> > G;
int Tcount;
int idx[maxn][2];

void add(int x, int num) {
	while (x <= 2*n) {
		C[x] += num;
		x += x & (-x);
	}
}
int sum(int x) {
	int ans = 0;
	while (x>0) {
		ans += C[x];
		x -= x & (-x);
	}
	return ans;
}

int vis[maxn*2];
void dfs(int u, int fa) {
	idx[u][0] = ++Tcount;
	vis[u] = 1;
	for (int i = 0; i<G[u].size(); ++i) {
		int v = G[u][i];
		if (v != fa&&!vis[v]) {
			dfs(v,u);
		}
	}
	idx[u][1] = ++Tcount;
}

int main() {
	freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	scanf("%d", &n);
	G.resize(n + 1);
	//_rep(i, 1, n)G[i].clear();
	_for(i, 0, n-1) {
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	Tcount = 0;
	memset(vis, 0, sizeof(vis));
	dfs(1, 0);

	for (int i = 1; i <= n * 2; ++i)C[i]=i-(i-(i&(-i)));
	for (int i = 0; i <= n; ++i)a[i] = 1;
	int Q; scanf("%d", &Q);
	char cmd[2];
	int x;
	while (Q--) {
		scanf("%s%d", cmd, &x);
		if (cmd[0] == 'Q') {
			printf("%d\n", (sum(idx[x][1]) - sum(idx[x][0] - 1)) / 2);
		}
		else {
			a[x] ^= 1;
			if (a[x]) add(idx[x][1], 1), add(idx[x][0], 1);
			else add(idx[x][1], -1), add(idx[x][0], -1);
		}
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/81544548
今日推荐