树链剖分

#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

posted @ 2026-07-20 21:17  宰杀方向盘  阅读(18)  评论(0)    收藏  举报