【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$

$演唱:Shakira$

Oh oh oh oh oooh

噢 噢 噢 噢

Oh oh oh oh oooh

噢 噢 噢 噢

Oh oh oh oh oooh

噢 噢 噢 噢

Oh oh oh oh oooh

噢 噢 噢 噢

I messed up tonight I lost another fight

刚搞砸了这一头 却又没顾得上那一头

I still mess up but I‘ll just start again

反复犯错却仍想重新来过

I keep falling down I keep on hitting the ground

不断跌倒 不断失败 也要不断重来

I always get up now to see what‘s next

想要触碰未来的心总会让我再站起来 继续大步前迈

Birds don‘t just fly they fall down and get up

在天空飞翔的鸟儿也难免会受伤会折翼 但也会重新振翅飞起

Nobody learns without getting it won

想要靠近蓝天就得有不怕坠落不怕受伤的勇气

I won‘t give up no I won‘t give in

我不会轻言放弃 谁也别想能让我放弃

Till I reach the end and then I‘ll start again

不停向前直到我达成心愿 然后又向更高的天空迈进

No I won‘t leave I wanna try everything

我不会逃避也不会迟疑 愿去尝试生命不同的绮丽

I wanna try even though I could fail

即使前路崎岖 未来阴晴不定 但至少我能体会到风雨过后的别样风景

I won‘t give up no I won‘t give in

我不会轻言放弃 谁也别想能让我放弃

Till I reach the end and then I‘ll start again

不停向前直到我达成心愿 然后又向更高的天空迈进

No I won‘t leave I wanna try everything

我不会逃避也不会迟疑 愿去尝试生命不同的绮丽

I wanna try even though I could fail

即使前路崎岖 未来阴晴不定 但至少我能体会到风雨过后的别样风景

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

去尝试生命不同的绮丽

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

去体验风雨过后的别样风景

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

让勇于尝试的勇气写就生命别样的意义

Oh oh oh oh oooh

噢 噢 噢 噢

Look at how far you‘ve come you filled your heart with love

当你想放弃 就回头看看你走过了多少崎岖 心中的那些爱又成就了一个怎样的你

Baby you‘ve done enough that cut your breath

别泄气 你已经做得够好了

Don‘t beat yourself up don‘t need to run so fast

别自暴自弃 也别太过心急

Sometimes we come last but we did our best

成功或许会迟些才降临 但尽过全力至少不会遗憾唏嘘

I won‘t give up no I won‘t give in

我不会轻言放弃 谁也别想能让我放弃

Till I reach the end and then I‘ll start again

不停向前直到我达成心愿 然后又向更高的天空迈进

No I won‘t leave I wanna try everything

我不会逃避也不会迟疑 愿去尝试生命不同的绮丽

I wanna try even though I could fail

即使前路崎岖 未来阴晴不定 但至少我能体会到风雨过后的别样风景

I won‘t give up no I won‘t give in

我不会轻言放弃 谁也别想能让我放弃

Till I reach the end and then I‘ll start again

不停向前直到我达成心愿 然后又向更高的天空迈进

No I won‘t leave I wanna try everything

我不会逃避也不会迟疑 愿去尝试生命不同的绮丽

I wanna try even though I could fail

即使前路崎岖 未来阴晴不定 但至少我能体会到风雨过后的别样风景

I‘ll keep on making those new mistakes

我会继续勇敢去体验 即使我还会不停犯错

I‘ll keep on making them every day

不断尝试不断犯错

Those new mistakes

不断犯错不断重新来过

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

不断尝试不断重新来过

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

不断体验生命中的不同结果

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

不断体验不断迈向更好的自我

Oh oh oh oh oooh

噢 噢 噢 噢

Try everything

让勇于尝试的勇气写就生命的别样意义

时间: 2024-12-18 17:54:39

【BZOJ 3531】【SDOI 2014】旅行 树链剖分的相关文章

BZOJ 3626 LNOI 2014 LCA 树链剖分

题目大意:给出一棵树,有n个问题,询问在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和. 思路:不会,然后看了题解,之后发现自己智商严重不足. 看到数据范围就知道一定要离线处理,就这个离线处理我估计以我的智商不看题解是肯定想不出来的.. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已标记了的点(包括自身).所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r

BZOJ 3531 SDOI 2014 旅行

题目大意 给出一个树,树上每个节点有两个权值,分别是这个节点的宗教评级和这个节点信仰的宗教.多次修改这两个权值,每次询问树上路径上的点的同一个宗教的最大评级和评级和. 思路 不要想太多,每个宗教建立一颗线段树,空间开不下考虑一下动态节点线段树.之后在每个线段树上维护一下树链剖分就行了. 你们想知道c的取值范围么? [0,10^5] CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #i

BZOJ 3531 SDOI2014 旅行 树链剖分

题目大意:给定一棵树,每一个点有一个权值和一个颜色.多次改变一些点的权值和颜色,多次求一条路径上与起点和终点颜色同样的点的权值和以及权值最大值 每种颜色开一个线段树 动态开节点 每一个点仅仅建一条链 这样空间复杂度是O(nlogn)的 然后就正常树链剖分即可了 #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

BZOJ 2157 旅行(树链剖分码农题)

写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v经过的边的权值最小值. 基于边权的树链剖分,放在线段树上变成了区间维护问题了,线段树维护4个量min,max,sum,tag就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. 时间复杂度O(N*log^3(N)) ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<

bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Status][Discuss] Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有

BZOJ 1787: [Ahoi2008]Meet 紧急集合( 树链剖分 )

这道题用 LCA 就可以水过去 , 但是我太弱了 QAQ 倍增写LCA总是写残...于是就写了树链剖分... 其实也不难写 , 线段树也不用用到 , 自己YY一下然后搞一搞就过了...速度还挺快的好像= = #9 ---------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algori

BZOJ 1103: [POI2007]大都市meg( 树链剖分 )

早上数学考挂了...欲哭无泪啊下午去写半个小时政治然后就又可以来刷题了.. 树链剖分 , 为什么跑得这么慢... --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #define rep( i , n ) for( int