BZOJ 3531SDOI 2014旅行 树链剖分

Posted abclzr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3531SDOI 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$

以上是关于BZOJ 3531SDOI 2014旅行 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3531 SDOI2014 旅行 树链剖分

[BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)

BZOJ.3531.旅行(树链剖分 动态开点)

树链剖分

B20J_3231_[SDOI2014]旅行_树链剖分+线段树

bzoj 3531 旅行