【BZOJ 3531】【SDOI 2014】旅行

因为有$10^5$个宗教,需要开$10^5$个线段树。

平时开的线段树是“满”二叉树,但在这个题中代表一个宗教的线段树管辖的区间有很多点都不属于这个宗教,也就不用“把枝叶伸到这个点上”,所以这样用类似主席树的数组动态开点来建立$10^5$个只有几个“树枝”的线段树,维护轻重链就可以了

线段树的$L,R,l,r$弄反了调了好久$QAQ$ $so$ $sad$

#include<cstdio>
#include<cstring>
#include<algorithm>
#define read(x) x=getint()
#define N 100003
using namespace std;
inline int getint() {int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = k * 10 + c - '0'; return k * fh;}
struct Tree {
	int l, r, ma, sm;
} T[4000010];
struct G {
	int nxt, to;
} E[N << 1];
int root[N], point[N], cnt = 0, n, q, W[N], C[N], sz[N], son[N], up[N];
int deep[N], fa[N], watch[N];
inline void ins(int x, int y) {E[++cnt].nxt = point[x]; E[cnt].to = y; point[x] = cnt;}
inline void _(int x) {
	sz[x] = 1;
	for(int tmp = point[x]; tmp; tmp = E[tmp].nxt) {
		int v = E[tmp].to;
		if (v == fa[x]) continue;
		fa[v] = x;
		deep[v] = deep[x] + 1;
		_(v);
		if (sz[v] > sz[son[x]])
			son[x] = v;
		sz[x] += sz[v];
	}
}
inline void __(int x) {
	watch[x] = ++cnt;
	if (!son[x]) return;
	up[son[x]] = up[x];
	__(son[x]);
	for(int tmp =point[x]; tmp; tmp = E[tmp].nxt) {
		int v = E[tmp].to;
		if (v == fa[x] || v == son[x]) continue;
		up[v] = v;
		__(v);
	}
}

inline void pushup(int pos) {
	T[pos].sm = T[T[pos].l].sm + T[T[pos].r].sm;
	T[pos].ma = max(T[T[pos].l].ma, T[T[pos].r].ma);
}
inline void update(int &pos, int l, int r, int to, int num) {
	if (pos == 0) pos = ++cnt;
	if (l == r) {T[pos].ma = T[pos].sm = num; return;}
	int mid = (l + r) >> 1;
	if (to <= mid) update(T[pos].l, l, mid, to, num);
	else update(T[pos].r, mid + 1, r, to, num);
	pushup(pos);
}
inline int Qsum(int pos, int L, int R, int l, int r) {
	if (L <= l && r <= R) return T[pos].sm;
	int mid = (l + r) >> 1, s = 0;
	if (L <= mid) s += Qsum(T[pos].l, L, R, l, mid);
	if (R > mid) s += Qsum(T[pos].r, L, R, mid + 1, r);
	return s;
}
inline int Qmax(int pos, int L, int R, int l, int r) {
	if (L <= l && r <= R) return T[pos].ma;
	int mid = (l + r) >> 1, s = 0;
	if (L <= mid) s = Qmax(T[pos].l, L, R, l, mid);
	if (R > mid) s = max(s, Qmax(T[pos].r, L, R, mid + 1, r));
	return s;
}

inline int Max(int CC, int x, int y) {
	int ans = 0;
	while (up[x] != up[y]) {
		if (deep[up[x]] < deep[up[y]]) swap(x, y);
		ans = max(ans, Qmax(root[CC], watch[up[x]], watch[x], 1, n));
		x = fa[up[x]];
	}
	if (deep[x] > deep[y]) swap(x, y);
	ans = max(ans, Qmax(root[CC], watch[x], watch[y], 1, n));
	return ans;
}
inline int Sum(int CC, int x, int y) {
	int ans = 0;
	while (up[x] != up[y]) {
		if (deep[up[x]] < deep[up[y]]) swap(x, y);
		ans += Qsum(root[CC], watch[up[x]], watch[x], 1, n);
		x = fa[up[x]];
	}
	if (deep[x] > deep[y]) swap(x, y);
	ans += Qsum(root[CC], watch[x], watch[y], 1, n);
	return ans;
}

int main() {
	read(n); read(q);
	for(int i = 1; i <= n; ++i)
		read(W[i]), read(C[i]);
	int u, v;
	for(int i = 1; i < n; ++i) {
		read(u); read(v);
		ins(u, v); ins(v, u);
	}
	_(1);
	up[1] = 1;
	cnt = 0;
	__(1);
	cnt = 0;
	for(int i = 1; i <= n; ++i)
		update(root[C[i]], 1, n, watch[i], W[i]);
	char c; int x, y;
	for(int i = 1; i <= q; ++i) {
		for(c = getchar(); c < 'A' || c > 'Z'; c = getchar());
		if (c == 'C') {
			c = getchar(); read(x); read(y);
			if (c == 'C') {
				update(root[C[x]], 1, n, watch[x], 0);
				C[x] = y;
				update(root[C[x]], 1, n, watch[x], W[x]);
			} else {
				update(root[C[x]], 1, n, watch[x], y);
				W[x] = y;
			}
		} else {
			c = getchar(); read(x); read(y);
			if (c == 'S')
				printf("%d\n", Sum(C[x], x, y));
			else
				printf("%d\n", Max(C[x], x, y));
		}
	}
	return 0;
}

hhhhhhhhhhhhhhhhhh调出来真的不容易啊,树链剖分怎么比$LCT$都难写!!!

 

$Try$ $Everything$

posted @ 2016-04-04 15:08  abclzr  阅读(179)  评论(0编辑  收藏  举报