树链剖分 之 重链剖分
视频
模板
就纪念一下
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】