_bzoj1036 [ZJOI2008]树的统计Count【树链剖分】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1036

保存模版。

执行qmax与qsum操作,往上爬的时候最开始的代码出了点小问题,往上爬的点应该是dep[top[u]]更深的点,而不是dep[u]更深的点。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

const int maxn = 30005;

int n, q, t1, t2, root;
int head[maxn], to[maxn << 1], next[maxn << 1], lb, cnt;
int siz[maxn], dep[maxn], fa[maxn], id[maxn], heavy[maxn], v[maxn], top[maxn], a[maxn];
char opr[10];
struct Node {
	int ql, qr, mx, sm;
} tree[maxn << 2];

inline void ist(int aa, int ss) {
	to[lb] = ss;
	next[lb] = head[aa];
	head[aa] = lb;
	++lb;
}
void dfs1(int r) {
	siz[r] = 1;
	dep[r] = dep[fa[r]] + 1;
	int mx = 0, id = 0;
	for (int j = head[r]; j != -1; j = next[j]) {
		if (to[j] != fa[r]) {
			fa[to[j]] = r;
			dfs1(to[j]);
			siz[r] += siz[to[j]];
			if (siz[to[j]] > mx) {
				mx = siz[id = to[j]];
			}
		}
	}
	heavy[r] = id;
}
void dfs2(int r, int tp) {
	if (!r) {
		return;
	}
	top[r] = tp;
	id[r] = ++cnt;
	a[cnt] = v[r];
	dfs2(heavy[r], tp);
	for (int j = head[r]; j != -1; j = next[j]) {
		if (to[j] != fa[r] && to[j] != heavy[r]) {
			dfs2(to[j], to[j]);
		}
	}
}
void make_tree(int p, int left, int right) {
	tree[p].ql = left;
	tree[p].qr = right;
	if (left == right) {
		tree[p].mx = tree[p].sm = a[left];
		return;
	}
	int mid = (left + right) >> 1;
	make_tree(p << 1, left, mid);
	make_tree(p << 1 | 1, mid + 1, right);
	tree[p].mx = std::max(tree[p << 1].mx, tree[p << 1 | 1].mx);
	tree[p].sm = tree[p << 1].sm + tree[p << 1 | 1].sm;
}
void upd(int p, int r, int value) {
	if (tree[p].ql == tree[p].qr) {
		tree[p].mx = tree[p].sm = value;
		return;
	}
	int mid = (tree[p].ql + tree[p].qr) >> 1;
	if (r <= mid) {
		upd(p << 1, r, value);
	}
	else {
		upd(p << 1 | 1, r, value);
	}
	tree[p].mx = std::max(tree[p << 1].mx, tree[p << 1 | 1].mx);
	tree[p].sm = tree[p << 1].sm + tree[p << 1 | 1].sm;
}
int getmax(int p, int left, int right) {
	if (tree[p].ql == left && tree[p].qr == right) {
		return tree[p].mx;
	}
	int mid = (tree[p].ql + tree[p].qr) >> 1;
	if (right <= mid) {
		return getmax(p << 1, left, right);
	}
	if (left > mid) {
		return getmax(p << 1 | 1, left, right);
	}
	return std::max(getmax(p << 1, left, mid), getmax(p << 1 | 1, mid + 1, right));
}
int getsum(int p, int left, int right) {
	if (tree[p].ql == left && tree[p].qr == right) {
		return tree[p].sm;
	}
	int mid = (tree[p].ql + tree[p].qr) >> 1;
	if (right <= mid) {
		return getsum(p << 1, left, right);
	}
	if (left > mid) {
		return getsum(p << 1 | 1, left, right);
	}
	return getsum(p << 1, left, mid) + getsum(p << 1 | 1, mid + 1, right);
}
int qmax(int u, int v) {
	int rt = -2147483646;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) {
			std::swap(u, v);
		}
		rt = std::max(rt, getmax(1, id[top[u]], id[u]));
		u = fa[top[u]];
	}
	if (dep[u] < dep[v]) {
		std::swap(u, v);
	}
	rt = std::max(rt, getmax(1, id[v], id[u]));
	return rt;
}
int qsum(int u, int v) {
	int rt = 0;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) {
			std::swap(u, v);
		}
		rt += getsum(1, id[top[u]], id[u]);
		u = fa[top[u]];
	}
	if (dep[u] < dep[v]) {
		std::swap(u, v);
	}
	rt += getsum(1, id[v], id[u]);
	return rt;
}

int main(void) {
	//freopen("in.txt", "r", stdin);
	unsigned seed;
	memset(head, -1, sizeof head);
	memset(next, -1, sizeof next);
	scanf("%d", &n);
	seed += n;
	for (int i = 1; i < n; ++i) {
		scanf("%d%d", &t1, &t2);
		ist(t1, t2);
		ist(t2, t1);
		seed += t1;
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%d", v + i);
	}
	
	srand(seed);
	root = rand() % n + 1;
	dfs1(root);
	dfs2(root, root);
	make_tree(1, 1, n);
	
	scanf("%d", &q);
	while (q--) {
		scanf("%s%d%d", opr, &t1, &t2);
		if (opr[1] == 'M') {
			printf("%d\n", qmax(t1, t2));
		}
		else if (opr[1] == 'S') {
			printf("%d\n", qsum(t1, t2));
		}
		else {
			upd(1, id[t1], t2);
		}
	}
	return 0;
}

  

posted @ 2016-12-08 14:15  ciao_sora  阅读(204)  评论(0编辑  收藏  举报