树链剖分【2023.1.31】

文章目录

  • 一.引入
  • 二.算法介绍
  • 三.实现
  • 四,例题
    • 1.【模板】 P 3384 P3384 P3384重链剖分/树链剖分
    • 2. P 2590 P2590 P2590树的统计
    • 3. P 3178 P3178 P3178树上操作
    • 4. P 2146 [ N O I 2015 ] P2146 [NOI2015] P2146[NOI2015] 软件包管理器
    • 5. P 4092 [ H E O I 2016 / T J O I 2016 ] P4092 [HEOI2016/TJOI2016] P4092[HEOI2016/TJOI2016]
    • 6. P 4315 P4315 P4315 月下“毛景树”
    • 7. P 1505 P1505 P1505 [国家集训队]旅游

一.引入

其实一个合理的引入对学生的兴趣影响很大

− c q b z g m \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad -cqbzgm cqbzgm

但是竞赛哪里有那么多兴趣 , 更重要的是恒心与毅 力    ( 虽然我没有   但是竞赛哪里有那么多兴趣,更重要的是恒心与毅力_{~~(虽然我没有~~} 但是竞赛哪里有那么多兴趣,更重要的是恒心与毅  (虽然我没有  

二.算法介绍

树链剖分,顾名思义,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、BST、SPLAY、线段树等)来维护每一条链。

− 源于百度百科 \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad -源于百度百科 源于百度百科

三.实现

光写个概念是无用的,我们还得去想办法实现.

我们先引入一点东西:

重儿子:一个结点的所有儿子中,子树节点数最多的那个

轻儿子:一个结点除重儿子以外的其他儿子

重链:从一个轻儿子开始,一直往他的重儿子走出的链

轻链:除重链外的其他链

然后看这张图:

树链剖分【2023.1.31】_第1张图片

我们用黄色来标记重儿子和重链:
树链剖分【2023.1.31】_第2张图片

再按照优先遍历重链对结点重新编号:

树链剖分【2023.1.31】_第3张图片

然后你就会发现,我们完成了 d f s dfs dfs序.

根据以上的流程,我们就可以写 d f s dfs dfs序了.

代码:

/*
dfs1:找出所有结点之间的关系 并求得每个结点的重儿子
dfs2:对所有结点重新编号
id[u]:dfs序后的编号
tmp[cnt]:序号cnt对应结点u
fa[u]:u的父亲结点
d[u]:u的深度
size[u]:u为根节点的子树的结点个数
son[u]:u的重儿子
top[u]:u所在的重链顶端结点
*/
void dfs1(int u){
	size[u] = 1, d[u] = d[fa[u]] + 1;//这个点本身size=1,深度为他父亲+1
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;//求重儿子
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ cnt, tmp[cnt] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);//一个点位于轻链底端,那么他的top必然是它本身
	}
}

然后我们就可以迎接例题了~~(终于写完了 h h h _{hhh} hhh~~

四,例题

1.【模板】 P 3384 P3384 P3384重链剖分/树链剖分

P 3384 P3384 P3384

1 x y z,表示将树从 x x x y y y 结点最短路径上所有节点的值都加上 z z z
2 x y,表示求树从 x x x y y y 结点最短路径上所有节点的值之和。
3 x z,表示将以 x x x 为根节点的子树内所有节点值都加上 z z z
4 x 表示求以 x x x 为根节点的子树内所有节点值之和

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson Tree[x].ls
#define rson Tree[x].rs
#define lz Tree[x].lazy
#define len(x) (Tree[x].r - Tree[x].l + 1)
struct edge{
	int next, to;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, ls, rs, sum, lazy;
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, r, mod, a[MAXN], root;
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN];
void add(int u, int v){
	g[++ cnt] = (edge){head[u], v};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1, d[u] = d[fa[u]] + 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ cnt, tmp[cnt] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int x){
	Tree[x].sum = (Tree[lson].sum + Tree[rson].sum) % mod;
}
void pushdown(int x){
	if(!lz)return ;
	Tree[lson].lazy += lz, Tree[lson].lazy %= mod;
	Tree[rson].lazy += lz, Tree[rson].lazy %= mod;
	Tree[lson].sum += lz * len(lson), Tree[lson].sum %= mod;
	Tree[rson].sum += lz * len(rson), Tree[rson].sum %= mod;
	lz = 0;
}
void build(int l, int r, int x){
	Tree[x].l = l, Tree[x].r = r;
  	if(l == r){
		Tree[x].sum = a[tmp[l]];
		return ;
	}
	int mid = l + r >> 1;
	lson = cnt ++, rson = cnt ++;
	build(l, mid, lson), build(mid + 1, r, rson);
	Tree[x].l = Tree[lson].l, Tree[x].r = Tree[rson].r;
	pushup(x);
}
void update(int l, int r, int k, int x){
	if(Tree[x].l >= l && Tree[x].r <= r){
		lz += k, lz %= mod;
		Tree[x].sum += len(x) * k, Tree[x].sum %= mod;
		return ;
	}
	pushdown(x);
	int mid = Tree[x].l + Tree[x].r >> 1;
	if(mid >= l)update(l, r, k, lson);
	if(mid < r)update(l, r, k, rson);
	pushup(x);
}
int query(int l, int r, int x){
	if(Tree[x].l >= l && Tree[x].r <= r)return Tree[x].sum;
	pushdown(x);
	int mid = Tree[x].l + Tree[x].r >> 1, sum = 0;
	if(mid >= l)sum += query(l, r, lson);
	if(mid < r)sum += query(l, r, rson);
	return sum % mod;
}
int sum(int l, int r){
	int res = 0;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res += query(id[top[l]], id[l], root), res %= mod;
		l = fa[top[l]];
	}
	if(id[l] > id[r])swap(l, r);
	return (res + query(id[l], id[r], root)) % mod;
}
void updates(int l, int r, int x){
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		update(id[top[l]], id[l], x, root);
		l = fa[top[l]];
	}
	if(id[l] > id[r])swap(l, r);
	update(id[l], id[r], x, root);
}
int main(){
	scanf("%d %d %d %d", &n, &m, &r, &mod);
	for(int i = 1; i <= n; i ++)scanf("%d", &a[i]);
	for(int i = 1; i < n; i ++){
		int u, v;
		scanf("%d %d", &u, &v);
		add(u, v), add(v, u);
	}
	cnt = 0, dfs1(r), dfs2(r, r);
	cnt = 0, build(1, n, root = cnt ++);
	for(int i = 1; i <= m; i ++){
		int opt, x, y, k;
		scanf("%d", &opt);
		if(opt == 1){
			scanf("%d %d %d", &x, &y, &k);
			updates(x, y, k);
		}
		else if(opt == 2){
			scanf("%d %d", &x, &y);
			printf("%d\n", sum(x, y));
		}
		else if(opt == 3){
			scanf("%d %d", &x, &y);
			update(id[x], id[x] + size[x] - 1, y, root);
		}
		else {
			scanf("%d", &x);
			printf("%d\n", query(id[x], id[x] + size[x] - 1, root));
		}
	}
	return 0;
}

2. P 2590 P2590 P2590树的统计

P 2590 P2590 P2590:

I. CHANGE u t : 把结点 u u u 的权值改为 t t t
II. QMAX u v: 询问从点 u u u 到点 v v v 的路径上的节点的最大权值。
III. QSUM u v: 询问从点 u u u 到点 v v v 的路径上的节点的权值和。

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
struct edge{
	int next, to;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, sum, maxn;
	Segment_Tree(){
		l = r = sum = 0;
		maxn = -0x3f3f3f3f;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, r, mod, a[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
void add(int u, int v){
	g[++ cnt] = (edge){head[u], v};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int pos){
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
	Tree[pos].maxn = max(Tree[lson].maxn, Tree[rson].maxn);
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r;
	if(l == r){
		Tree[pos].sum = Tree[pos].maxn = a[tmp[l]];
		return ;
	}
	int mid = l + r >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(pos);
}
void update(int pos, int k, int x){
	if(Tree[pos].l == Tree[pos].r){
		Tree[pos].sum = Tree[pos].maxn = x;
		return ;
	}
	int mid = Tree[pos].l + Tree[pos].r >> 1;
	if(k <= mid)update(lson, k, x);
	else update(rson, k, x);
	pushup(pos);
}
int querymax(int pos, int ql, int qr){
	if(ql <= Tree[pos].l && Tree[pos].r <= qr)return Tree[pos].maxn;
	int mid = Tree[pos].l + Tree[pos].r >> 1, maxn = -0x3f3f3f3f;
	if(ql <= mid)maxn = max(maxn, querymax(lson, ql, qr));
	if(qr > mid) maxn = max(maxn, querymax(rson, ql, qr));
	return maxn;
}
int querysum(int pos, int l, int r, int ql, int qr){
	if(ql <= l && r <= qr)return Tree[pos].sum;
	int mid = l + r >> 1, sum = 0;
	if(ql <= mid)sum += querysum(lson, l, mid, ql, qr);
	if(qr > mid)sum += querysum(rson, mid + 1, r, ql, qr);
	return sum;
}
int getmax(int l, int r){
	int res = -0x3f3f3f3f;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res = max(res, querymax(1, id[top[l]], id[l]));
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return max(res, querymax(1, id[l], id[r]));
}
int getsum(int l, int r){
	int res = 0;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res += querysum(1, 1, n, id[top[l]], id[l]);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return res + querysum(1, 1, n, id[l], id[r]);
}
int main(){
	scanf("%d", &n);
	for(int i = 1; i < n; i ++){
		int u, v;
		scanf("%d %d", &u, &v);
		add(u, v), add(v, u);
	}
	for(int i = 1; i <= n; i ++)scanf("%d", &a[i]);
	scanf("%d", &m);
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i <= m; i ++){
		string opt;
		int x, y;
		cin >> opt;
		if(opt == "CHANGE"){
			scanf("%d %d", &x, &y);
			update(1, id[x], y);
		}
		else if(opt == "QMAX"){
			scanf("%d %d", &x, &y);
			printf("%d\n", getmax(x, y));
		}
		else{
			scanf("%d %d", &x, &y);
			printf("%d\n", getsum(x, y));
		}
	}
	return 0;
}

3. P 3178 P3178 P3178树上操作

P3178

操作 1 1 1 :把某个节点 x x x 的点权增加 a a a
操作 2 2 2 :把某个节点 x x x 为根的子树中所有点的点权都增加 a 。
操作 3 3 3 :询问某个节点 x x x 到根的路径中所有点的点权和。

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
#define len(x) (Tree[x].r - Tree[x].l + 1)
#define lz Tree[pos].lazy
#define int long long
struct edge{
	int next, to;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, ls, rs, sum, lazy;
	Segment_Tree(){
		l = r = sum = 0;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, r, mod, a[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
void add(int u, int v){
	g[++ cnt] = (edge){head[u], v};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushdown(int pos){
	if(!lz)return ;
	Tree[lson].lazy += lz;
	Tree[rson].lazy += lz;
	Tree[lson].sum += lz * len(lson);
	Tree[rson].sum += lz * len(rson);
	lz = 0;
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r;
	if(l == r){
		Tree[pos].sum = a[tmp[l]];
		return ;
	}
	int mid = l + r >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
void update(int pos, int k, int x){
	if(Tree[pos].l == Tree[pos].r){
		Tree[pos].sum += x;
		return ;
	}
	pushdown(pos);
	int mid = Tree[pos].l + Tree[pos].r >> 1;
	if(k <= mid)update(lson, k, x);
	else update(rson, k, x);
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
void update1(int l, int r, int k, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		lz += k;
		Tree[pos].sum += len(pos) * k;
		return ;
	}
	pushdown(pos);
	int mid = Tree[pos].l + Tree[pos].r >> 1;
	if(mid >= l)update1(l, r, k, lson);
	if(mid < r)update1(l, r, k, rson);
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
int querysum(int pos, int l, int r, int ql, int qr){
	if(ql <= l && r <= qr)return Tree[pos].sum;
	int mid = l + r >> 1, sum = 0;
	pushdown(pos);
	if(ql <= mid)sum += querysum(lson, l, mid, ql, qr);
	if(qr > mid)sum += querysum(rson, mid + 1, r, ql, qr);
	return sum;
}
int getsum(int l, int r){
	int res = 0;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res += querysum(1, 1, n, id[top[l]], id[l]);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return res + querysum(1, 1, n, id[l], id[r]);
}
signed main(){
	scanf("%lld %lld", &n, &m);
	for(int i = 1; i <= n; i ++)scanf("%lld", &a[i]);
	for(int i = 1; i < n; i ++){
		int u, v;
		scanf("%lld %lld", &u, &v);
		add(u, v), add(v, u);
	}
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i <= m; i ++){
		int opt, x, y;
		scanf("%lld", &opt);
		if(opt == 1){
			scanf("%lld %lld", &x, &y);
			update(1, id[x], y);
		}
		else if(opt == 2){
			scanf("%lld %lld", &x, &y);
			update1(id[x], id[x] + size[x] - 1, y, 1);
		}
		else{
			scanf("%lld", &x);
			printf("%lld\n", getsum(1, x));
		}
	}
	return 0;
}

4. P 2146 [ N O I 2015 ] P2146 [NOI2015] P2146[NOI2015] 软件包管理器

P2146

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
#define len(x) (Tree[x].r - Tree[x].l + 1)
#define lz Tree[pos].lazy
struct edge{
	int next, to;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, sum, lazy;
	Segment_Tree(){
		l = r = sum = 0;
		lazy = -1;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, a[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
void add(int u, int v){
	g[++ cnt] = (edge){head[u], v};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int pos){
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
void pushdown(int pos){
	if(lz == -1)return ;
	Tree[lson].lazy = Tree[rson].lazy = lz;
	Tree[lson].sum = lz * len(lson);
	Tree[rson].sum = lz * len(rson);
	lz = -1;
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r;
	if(l == r){
		Tree[pos].sum = 0;
		return ;
	}
	int mid = l + r >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(pos);
}
void update(int l, int r, int k, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		lz = k;
		Tree[pos].sum = len(pos) * k;
		return ;
	}
	pushdown(pos);
	int mid = Tree[pos].l + Tree[pos].r >> 1;
	if(mid >= l)update(l, r, k, lson);
	if(mid < r)update(l, r, k, rson);
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
void change(int l, int r, int x){
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		update(id[top[l]], id[l], x, 1);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	update(id[l], id[r], x, 1);
}
int main(){
	scanf("%d", &n);
	for(int i = 2; i <= n; i ++){
		int v;
		scanf("%d", &v);
		v ++;
		add(i, v), add(v, i);
	}
	scanf("%d", &m);
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i <= m; i ++){
		string opt;
		int x;
		cin >> opt >> x;
		x ++;
		int tot = Tree[1].sum;
		if(opt == "install"){
			change(1, x, 1);
			printf("%d\n", abs(Tree[1].sum - tot));
		}
		else{
			update(id[x], id[x] + size[x] - 1, 0, 1);
			printf("%d\n", abs(Tree[1].sum - tot));
		}
	}
	return 0;
}

5. P 4092 [ H E O I 2016 / T J O I 2016 ] P4092 [HEOI2016/TJOI2016] P4092[HEOI2016/TJOI2016]

P4092

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
struct edge{
	int next, to;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, deep;
	Segment_Tree(){
		l = r = 0;
		deep = -0x3f3f3f3f;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, a[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
void add(int u, int v){
	g[++ cnt] = (edge){head[u], v};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int pos){
	Tree[pos].deep = max(Tree[lson].deep, Tree[rson].deep);
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r;
	if(l == r)return ;
	int mid = l + r >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
}
void update(int l, int r, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		Tree[pos].deep = l;
		return ;
	}
	int mid = Tree[pos].l + Tree[pos].r >> 1;
	if(mid >= l)update(l, r, lson);
	if(mid < r)update(l, r, rson);
	pushup(pos);
}
int query(int pos, int ql, int qr){
	if(ql <= Tree[pos].l && Tree[pos].r <= qr)return Tree[pos].deep;
	int mid = Tree[pos].l + Tree[pos].r >> 1, maxn = -0x3f3f3f3f;
	if(ql <= mid)maxn = max(maxn, query(lson, ql, qr));
	if(qr > mid) maxn = max(maxn, query(rson, ql, qr));
	return maxn;
}
int getmax(int l, int r){
	int res = -0x3f3f3f3f;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res = max(res, query(1, id[top[l]], id[l]));
		if(res != -0x3f3f3f3f)return tmp[res];
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return tmp[query(1, id[l], id[r])];
}
int main(){
	scanf("%d %d", &n, &m);
	for(int i = 1; i < n; i ++){
		int u, v;
		scanf("%d %d", &u, &v);
		add(u, v), add(v, u);
	}
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	update(1, 1, 1);
	for(int i = 1; i <= m; i ++){
		char opt;
		int x;
		cin >> opt >> x;
		if(opt == 'C')update(id[x], id[x], 1);
		else printf("%d\n", getmax(x, 1));
	}
	return 0;
}

6. P 4315 P4315 P4315 月下“毛景树”

P4315

#include
using namespace std;
const int MAXN = 1e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
#define len(x) (Tree[x].r - Tree[x].l + 1)
#define lz Tree[pos].lazy
#define tg Tree[pos].tag
#define int long long
struct edge{
	int next, to, w;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, maxn, lazy, tag;
	Segment_Tree(){
		l = r = maxn = lazy = 0;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, r, mod, a[MAXN], b[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
template<typename T>
void read(T &x){
	x = 0;
	T f = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0'){
		if(ch == '-')f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	x *= f;
}
template<typename T>
void write(T x){
	if(x < 0){
		x = -x;
		putchar('-');
	}
	if(x >= 10)write(x / 10);
	putchar(x % 10 + 48);
}
void add(int u, int v, int w){
	g[++ cnt] = (edge){head[u], v, w};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		a[v] = g[i].w;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int pos){
	Tree[pos].maxn = max(Tree[lson].maxn, Tree[rson].maxn);
}
void pushdown(int pos){
	if(lz >= 0){
		Tree[lson].tag = Tree[rson].tag = 0;
		Tree[lson].lazy = Tree[rson].lazy = Tree[lson].maxn = Tree[rson].maxn = lz;
		lz = -1;	
	}
	if(tg){
		Tree[lson].tag += tg, Tree[rson].tag += tg;
		Tree[lson].maxn += tg, Tree[rson].maxn += tg;
		tg = 0;
	}
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r, Tree[pos].lazy = -1;
	if(l == r){
		Tree[pos].maxn = a[tmp[l]];
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(pos);
}
void update(int pos, int k, int x){
	if(Tree[pos].l == Tree[pos].r){
		Tree[pos].maxn = lz = x;
		tg = 0;
		return ;
	}
	pushdown(pos);
	int mid = (Tree[pos].l + Tree[pos].r) >> 1;
	if(k <= mid)update(lson, k, x);
	else update(rson, k, x);
	pushup(pos);
}
void update1(int l, int r, int k, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		tg += k;
		Tree[pos].maxn += k;
		return ;
	}
	pushdown(pos);
	int mid = (Tree[pos].l + Tree[pos].r) >> 1;
	if(mid >= l)update1(l, r, k, lson);
	if(mid < r)update1(l, r, k, rson);
	pushup(pos);
}
void updates1(int l, int r, int x){
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		update1(id[top[l]], id[l], x, 1);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	update1(id[l] + 1, id[r], x, 1);
}
void update2(int l, int r, int k, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		lz = Tree[pos].maxn = k;
		tg = 0;
		return ;
	}
	pushdown(pos);
	int mid = (Tree[pos].l + Tree[pos].r) >> 1;
	if(mid >= l)update2(l, r, k, lson);
	if(mid < r)update2(l, r, k, rson);
	pushup(pos);
}
void updates(int l, int r, int x){
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		update2(id[top[l]], id[l], x, 1);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	update2(id[l] + 1, id[r], x, 1);
}
int query(int pos, int l, int r, int ql, int qr){
	if(ql <= l && r <= qr)return Tree[pos].maxn;
	int mid = (l + r) >> 1, maxn = -0x3f3f3f3f;
	pushdown(pos);
	if(ql <= mid)maxn = max(maxn, query(lson, l, mid, ql, qr));
	if(qr > mid)maxn = max(maxn, query(rson, mid + 1, r, ql, qr));
	return maxn;
}
int getmax(int l, int r){
	int res = -0x3f3f3f3f;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res = max(res, query(1, 1, n, id[top[l]], id[l]));
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return max(res, query(1, 1, n, id[l] + 1, id[r]));
	return res;
}
int u[MAXN], v[MAXN], w[MAXN];
signed main(){
	read(n);
	for(int i = 1; i < n; i ++){
		read(u[i]), read(v[i]), read(w[i]);
		add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
	}
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i < n; i ++){
		if(fa[u[i]] == v[i]) son[i] = u[i];
		else son[i] = v[i];
	}
	string opt;
	while(1){
		cin >> opt;
		if(opt == "Stop")break;
		int x, y, k;
		if(opt == "Change"){
			read(x), read(y);
			update(1, id[son[x]], y);
		}
		else if(opt == "Cover"){
			read(x), read(y), read(k);
			updates(x, y, k);
		}
		else if(opt == "Add"){
			read(x), read(y), read(k);
			updates1(x, y, k);
		}
		else{
			read(x), read(y);
			write(getmax(x, y));
			putchar('\n');
		}
	}
	return 0;
} 

7. P 1505 P1505 P1505 [国家集训队]旅游

P1505

#include
using namespace std;
const int MAXN = 2e5 + 5;
#define lson pos << 1
#define rson pos << 1 | 1
#define lz Tree[pos].lazy
#define int long long
struct edge{
	int next, to, w;
}g[MAXN << 1];
struct Segment_Tree{
	int l, r, maxn, minn, sum, lazy;
	Segment_Tree(){
		l = r = lazy = 0;
		maxn = -0x3f3f3f3f;
		minn = 0x3f3f3f3f;
	}
}Tree[MAXN << 2];
int head[MAXN << 1], cnt;
int n, m, r, mod, a[MAXN], b[MAXN];
int fa[MAXN], d[MAXN], son[MAXN], size[MAXN], top[MAXN], id[MAXN], tmp[MAXN], tot;
template<typename T>
void read(T &x){
	x = 0;
	T f = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0'){
		if(ch == '-')f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	x *= f;
}
template<typename T>
void write(T x){
	if(x < 0){
		x = -x;
		putchar('-');
	}
	if(x >= 10)write(x / 10);
	putchar(x % 10 + 48);
}
void add(int u, int v, int w){
	g[++ cnt] = (edge){head[u], v, w};
	head[u] = cnt;
}
void dfs1(int u){
	size[u] = 1;
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v == fa[u])continue;
		a[v] = g[i].w;
		d[v] = d[u] + 1;
		fa[v] = u;
		dfs1(v);
		size[u] += size[v];
		if(size[son[u]] < size[v])son[u] = v;
	}
}
void dfs2(int u, int front){
	top[u] = front, id[u] = ++ tot, tmp[tot] = u;
	if(son[u])dfs2(son[u], front);
	for(int i = head[u]; i; i = g[i].next){
		int v = g[i].to;
		if(v != fa[u] && v != son[u])dfs2(v, v);
	}
}
void pushup(int pos){
	Tree[pos].maxn = max(Tree[lson].maxn, Tree[rson].maxn);
	Tree[pos].minn = min(Tree[lson].minn, Tree[rson].minn);
	Tree[pos].sum = Tree[lson].sum + Tree[rson].sum;
}
void pushdown(int pos){
	if(!lz)return ;
	Tree[lson].lazy ^= 1, Tree[rson].lazy ^= 1;
	Tree[lson].sum = -Tree[lson].sum, Tree[rson].sum = -Tree[rson].sum;
	Tree[lson].maxn = -Tree[lson].maxn, Tree[rson].maxn = -Tree[rson].maxn;
	Tree[lson].minn = -Tree[lson].minn, Tree[rson].minn = -Tree[rson].minn;
	swap(Tree[lson].maxn, Tree[lson].minn);
	swap(Tree[rson].maxn, Tree[rson].minn);
	lz = 0;
}
void build(int pos, int l, int r){
	Tree[pos].l = l, Tree[pos].r = r;
	if(l == r){
		Tree[pos].minn = Tree[pos].sum = Tree[pos].maxn = a[tmp[l]];
		return ;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(pos);
}
void update(int pos, int k, int x){
	if(Tree[pos].l == Tree[pos].r){
		Tree[pos].maxn = Tree[pos].minn = Tree[pos].sum = x;
		return ;
	}
	pushdown(pos);
	int mid = (Tree[pos].l + Tree[pos].r) >> 1;
	if(k <= mid)update(lson, k, x);
	else update(rson, k, x);
	pushup(pos);
}
void update1(int l, int r, int pos){
	if(Tree[pos].l >= l && Tree[pos].r <= r){
		lz ^= 1;
		Tree[pos].sum = -Tree[pos].sum, Tree[pos].maxn = -Tree[pos].maxn, Tree[pos].minn = -Tree[pos].minn;
		swap(Tree[pos].maxn, Tree[pos].minn);
		return ;
	}
	pushdown(pos);
	int mid = (Tree[pos].l + Tree[pos].r) >> 1;
	if(mid >= l)update1(l, r, lson);
	if(mid < r)update1(l, r, rson);
	pushup(pos);
}
void updates(int l, int r){
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		update1(id[top[l]], id[l], 1);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);	
	update1(id[l] + 1, id[r], 1);
}
int querymax(int pos, int ql, int qr){
	if(ql <= Tree[pos].l && Tree[pos].r <= qr)return Tree[pos].maxn;
	int mid = (Tree[pos].l + Tree[pos].r) >> 1, maxn = -0x3f3f3f3f;
	pushdown(pos);
	if(ql <= mid)maxn = max(maxn, querymax(lson, ql, qr));
	if(qr > mid)maxn = max(maxn, querymax(rson, ql, qr));
	pushup(pos);
	return maxn;
}
int querymin(int pos, int ql, int qr){
	if(ql <= Tree[pos].l && Tree[pos].r <= qr)return Tree[pos].minn;
	int mid = (Tree[pos].l + Tree[pos].r) >> 1, minn = 0x3f3f3f3f;
	pushdown(pos);
	if(ql <= mid)minn = min(minn, querymin(lson, ql, qr));
	if(qr > mid)minn = min(minn, querymin(rson, ql, qr));
	pushup(pos);
	return minn;
}
int querysum(int pos, int ql, int qr){
	if(ql <= Tree[pos].l && Tree[pos].r <= qr)return Tree[pos].sum;
	int mid = (Tree[pos].l + Tree[pos].r) >> 1, sum = 0;
	pushdown(pos);
	if(ql <= mid)sum += querysum(lson, ql, qr);
	if(qr > mid)sum += querysum(rson, ql, qr);
	pushup(pos);
	return sum;
}
int getmax(int l, int r){
	int res = -0x3f3f3f3f;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res = max(res, querymax(1, id[top[l]], id[l]));
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return max(res, querymax(1, id[l] + 1, id[r]));
}
int getmin(int l, int r){
	int res = 0x3f3f3f3f;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res = min(res, querymin(1, id[top[l]], id[l]));
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return min(res, querymin(1, id[l] + 1, id[r]));
}
int getsum(int l, int r){
	int res = 0;
	while(top[l] != top[r]){
		if(d[top[l]] < d[top[r]])swap(l, r);
		res += querysum(1, id[top[l]], id[l]);
		l = fa[top[l]];
	}
	if(d[l] > d[r])swap(l, r);
	return (res + querysum(1, id[l] + 1, id[r]));
}
int u[MAXN], v[MAXN], w[MAXN];
signed main(){
	read(n);
	for(int i = 1; i < n; i ++){
		read(u[i]), read(v[i]), read(w[i]);
		u[i] ++, v[i] ++;
		add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
	}
	fa[1] = d[1] = 1;
	dfs1(1), dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i < n; i ++){
		if(fa[u[i]] == v[i]) son[i] = u[i];
		else son[i] = v[i];
	}
	read(m);
	string opt;
	while(m --){
		cin >> opt;
		int x, y;
		read(x), read(y);
		if(opt == "C"){
			update(1, id[son[x]], y);
		}
		else if(opt == "N"){
			updates(x + 1, y + 1);
		}
		else if(opt == "SUM"){
			write(getsum(x + 1, y + 1));
			putchar('\n');
		}
		else if(opt == "MAX"){
			write(getmax(x + 1, y + 1));
			putchar('\n');
		}
		else{
			write(getmin(x + 1, y + 1));
			putchar('\n');			
		}
	}
	return 0;
} 

你可能感兴趣的:(树链剖分,数据结构,算法,深度优先)