树链剖分

📅 2026/7/21 23:09:53 👁️ 阅读次数 📝 编程学习
树链剖分
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n, m, r, p, w[N];
int tot, h[N], e[2*N], nxt[2*N];
void add(int u, int v){nxt[++tot] = h[u];h[u] = tot;e[tot] = v;
}
struct Node{int l, r, lazy, sum;
} tr[4*N];
void pushup(int u){tr[u].sum = (tr[u<<1].sum + tr[u<<1|1].sum) % p;
}
void pushdown(int u){if(tr[u].lazy){tr[u<<1].lazy = (tr[u<<1].lazy + tr[u].lazy) % p;tr[u<<1].sum = (tr[u<<1].sum + 1ll*tr[u].lazy * (tr[u<<1].r - tr[u<<1].l + 1)) % p;tr[u<<1|1].lazy = (tr[u<<1|1].lazy + tr[u].lazy) % p;tr[u<<1|1].sum = (tr[u<<1|1].sum + 1ll*tr[u].lazy * (tr[u<<1|1].r - tr[u<<1|1].l + 1)) % p;tr[u].lazy = 0;}
}
void build(int u, int l, int r){tr[u].l = l;tr[u].r = r;if(l == r) return ;int mid = (l+r)>>1;build(u<<1, l, mid);build(u<<1|1, mid+1, r);
}
void modify(int u, int L, int R, int val){int l = tr[u].l, r = tr[u].r;if(l >= L && r <= R){tr[u].lazy = (tr[u].lazy+val)%p;tr[u].sum = (tr[u].sum + 1ll*val*(r-l+1))%p;return ;}if(tr[u].lazy) pushdown(u);int mid = (l+r)>>1;if(mid >= L) modify(u<<1, L, R, val);if(mid+1 <= R) modify(u<<1|1, L, R, val);pushup(u);
}
int query(int u, int L, int R){if(tr[u].lazy) pushdown(u);int l = tr[u].l, r = tr[u].r;if(l >= L && r <= R) return tr[u].sum;int ans = 0, mid = (l+r)>>1;if(mid >= L) ans = (ans + query(u<<1, L, R)) % p;if(mid+1 <= R) ans = (ans + query(u<<1|1, L, R)) % p;return ans;
}
int f[N], son[N], siz[N], deep[N];
void dfs1(int u){siz[u] = 1;int mx = 0;for(int i = h[u]; i; i = nxt[i]){int v = e[i];if(v == f[u]) continue;f[v] = u;deep[v] = deep[u]+1;dfs1(v);if(siz[v] > mx) mx = siz[v], son[u] = v;siz[u] += siz[v];}
}
int top[N], dfn[N], idx;
void dfs2(int u){dfn[u] = ++idx;if(!son[u]) return ;top[son[u]] = top[u];dfs2(son[u]);for(int i = h[u]; i; i = nxt[i]){int v = e[i];if(dfn[v]) continue;top[v] = v;dfs2(v);}
}
void add_path(int x, int y, int val){while(top[x] != top[y]){if(deep[top[x]] < deep[top[y]]) swap(x, y);modify(1, dfn[top[x]], dfn[x], val);x = f[top[x]];}if(deep[x] > deep[y]) swap(x, y);modify(1, dfn[x], dfn[y], val);
}
int ask_path(int x, int y){int ans = 0;while(top[x] != top[y]){if(deep[top[x]] < deep[top[y]]) swap(x, y);ans = (ans+query(1, dfn[top[x]], dfn[x])) % p;x = f[top[x]];}if(deep[x] > deep[y]) swap(x, y);ans = (ans+query(1, dfn[x], dfn[y])) % p;return ans;
}
void add_tree(int x, int val){modify(1, dfn[x], dfn[x]+siz[x]-1, val);
}
int ask_tree(int x){return query(1, dfn[x], dfn[x]+siz[x]-1);
}
int main(){scanf("%d%d%d%d", &n, &m, &r, &p);build(1, 1, n);for(int i = 1; i <= n; i++) scanf("%d", &w[i]);for(int i = 1; i < n; i++){int u, v;scanf("%d%d", &u, &v);add(u, v);add(v, u);}dfs1(r);dfs2(r);for(int i = 1; i <= n; i++) modify(1, dfn[i], dfn[i], w[i]);while(m--){int opt, x, y, z;scanf("%d", &opt);if(opt == 1){scanf("%d%d%d", &x, &y, &z);add_path(x, y, z);}else if(opt == 2){scanf("%d%d", &x, &y);printf("%d\n", ask_path(x, y));}else if(opt == 3){scanf("%d%d", &x, &z);add_tree(x, z);}else{scanf("%d", &x);printf("%d\n", ask_tree(x));}}return 0;
}

树剖+线段树, P3384