树链剖分 之 重链剖分

视频

模板


就纪念一下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" = "<<x<<endl;
const int N = 1e5 + 5;
int n, m, root, M;
ll tmp[N], w[N];
int go[N], dep[N], son[N], siz[N], top[N], num, dfn[N];
struct segment_tree {
	int l, r;
	ll sum, tag;
	#define siz(x) (tree[x].r - tree[x].l + 1)
	#define lson (x << 1)
	#define rson (x << 1 | 1)
}tree[N << 2];//根据 dfs序 建的线段树
vector<int> g[N];
inline int read() {
	int s = 0, f = 1; char c = getchar();
	while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { s = (s << 1) + (s << 3) + (c ^ 48); c = getchar(); }
	return s * f;
}
void build(int x, int l, int r) {
	tree[x].l = l, tree[x].r = r;
	if (l == r) {
		tree[x].sum = w[l] % M;
		return;
	}
	int mid = l + r >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	tree[x].sum = (tree[lson].sum + tree[rson].sum) % M;
}
void pushdown(int x) {
	if (tree[x].tag) {
		tree[lson].tag = (tree[lson].tag + tree[x].tag) % M;
		tree[rson].tag = (tree[rson].tag + tree[x].tag) % M;
		tree[lson].sum = (tree[lson].sum + tree[x].tag * siz(lson) % M) % M;
		tree[rson].sum = (tree[rson].sum + tree[x].tag * siz(rson) % M) % M;
		tree[x].tag = 0;
	}
}
void update(int x, int l, int r, int c) {
	if (l <= tree[x].l && tree[x].r <= r) {
		tree[x].sum = (tree[x].sum + (ll)c * siz(x) % M) % M;
		tree[x].tag = (tree[x].tag + c) % M;
		return;
	}
	pushdown(x);
	if (l <= tree[lson].r)update(lson, l, r, c);
	if (tree[rson].l <= r)update(rson, l, r, c);
	tree[x].sum = (tree[lson].sum + tree[rson].sum) % M;
}
ll query(int x, int l, int r) {
	if (l <= tree[x].l && tree[x].r <= r)return tree[x].sum;
	pushdown(x);
	ll sum = 0;
	if (l <= tree[lson].r)sum += query(lson, l, r);
	if (tree[rson].l <= r)sum += query(rson, l, r);
	return sum % M;
}
void dfs1(int x, int fa) {
	siz[x] = 1;
	dep[x] = dep[fa] + 1;
	go[x] = fa;
	int maxn_son = 0;
	for (int i = 0; i < g[x].size(); i++) {
		int t = g[x][i];
		if (t == fa)continue;
		dfs1(t, x);
		siz[x] += siz[t];
		if (siz[t] > maxn_son) {
			maxn_son = siz[t];
			son[x] = t;
		}
	}
}
void dfs2(int x, int t) {
	dfn[x] = ++num;
	top[x] = t;
	w[num] = tmp[x];
	if (!son[x])return;
	dfs2(son[x], t);//要让重链的时间戳是连续的
	for (int i = 0; i < g[x].size(); i++) {
		int to = g[x][i];
		if (to == go[x] || to == son[x])continue;
		dfs2(to, to);
	}
}
void update_chain(int x,int y,int z) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]])swap(x, y);
		update(1, dfn[top[x]], dfn[x], z);
		x = go[top[x]];
	}
	if (dfn[x] > dfn[y])swap(x, y);//让 x 成为深度小的那个
	update(1, dfn[x], dfn[y], z);
}
ll query_chain(int x, int y) {
	ll ans = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]])swap(x, y);
		ans = (ans + query(1,dfn[top[x]],dfn[x])) % M;
		x = go[top[x]];
	}
	if (dfn[x] > dfn[y])swap(x, y);
	return (ans + query(1, dfn[x], dfn[y])) % M;
}
int main() {
	n = read(), m = read(), root = read(), M = read();
	for (int i = 1; i <= n; i++)tmp[i] = read();
	for (int i = 1; i < n; i++) {
		int u = read(), v = read();
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs1(root, root);
	dfs2(root, root);
	build(1, 1, n);
	//只有修改或者查询的时候用到 dfn数组
	for (int i = 1; i <= m; i++) {
		int opt = read(), x, y, z;
		if (opt == 1) {
			int x = read(), y = read(), z = read();
			update_chain(x, y, z);
		}
		if (opt == 2) {
			int x = read(), y = read();
			printf("%lld\n", query_chain(x, y));
		}
		if (opt == 3) {
			x = read(), z = read();
			update(1, dfn[x], dfn[x] + siz[x] - 1, z);
		}
		if (opt == 4) {
			x = read();
			printf("%lld\n", query(1, dfn[x], dfn[x] + siz[x] - 1));
		}
	}
	return 0;
}
posted @   今添  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示