求助树链剖分,马蜂还可以
查看原帖
求助树链剖分,马蜂还可以
1192413
jimmy9_666楼主2024/8/9 13:31
#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (x<<1)|1

using namespace std;

const int N = 2 * 1e5 + 1;

struct tree {
	ll l, r;
	ll val;
	ll lazy;
};

ll n, m, root, p;
ll a[N], fa[N], son[N], siz[N], top[N], dfn[N], rnk[N], dep[N];
// a:权值  fa:父亲  son:重子节点  siz:子树大小  top:链顶  dfn:DFS序  rnk:DFS序对应编号  dep:深度 
ll cnt;
vector<ll> g[N];


tree t[N << 2]; // 线段树 

void pushup(ll x) {
	t[x].val = (t[ls(x)].val + t[rs(x)].val);
	return;
}

void pushdown(ll x) {
	if (t[x].l == t[x].r) {
		t[x].lazy = 0;
		return;
	}
	t[ls(x)].val += (t[ls(x)].r - t[ls(x)].l + 1) * t[x].lazy;
	t[rs(x)].val += (t[rs(x)].r - t[rs(x)].l + 1) * t[x].lazy;
	t[ls(x)].lazy += t[x].lazy, t[rs(x)].lazy += t[x].lazy;
	return;
}

void build(ll l, ll r, ll x) {
	t[x].l = l, t[x].r = r;
	if (l == r) {
		t[x].val = a[rnk[l]];
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, ls(x)), build(mid + 1, r, rs(x));
	pushup(x);
	return;
}

void add(ll l, ll r, ll k, ll x) {
	if (t[x].l > r || t[x].r < l)
		return;
	if (l <= t[x].l && t[x].r <= r) {
		t[x].val += (t[x].r - t[x].l + 1) * k;
		t[x].lazy += k;
		return;
	}
	if (t[x].lazy)
		pushdown(x);
	add(l, r, k, ls(x)), add(l, r, k, rs(x));
	pushup(x);
	return;
}

ll ask(ll l, ll r, ll x) {
	if (t[x].l > r || t[x].r < l)
		return 0;
	if (l <= t[x].l && t[x].r <= r)
		return t[x].val;
	if (t[x].lazy)
		pushdown(x);
	ll sum = (ask(l, r, ls(x)) + ask(l, r, rs(x)));
	pushup(x);
	return sum;
}

// 以上是线段树 

void dfs1(ll now, ll fath) { // 求fa, dep, siz, son
	fa[now] = fath, dep[now] = dep[fath] + 1;
	siz[now] = 1;
	for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
		ll v = g[now][i];
		if (v == fath)
			continue;
		dfs1(v, now);
		siz[now] += siz[v];
		if (siz[v] > siz[son[now]])
			son[now] = v;
	}
	return;
}

void dfs2(ll now, ll anc) { // 求top, dfn, rnk
	top[now] = anc;
	dfn[now] = ++ cnt;
	rnk[cnt] = now;
	if (!son[now])
		return;
	dfs2(son[now], anc);
	for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
		ll v = g[now][i];
		if (v != fa[now] && v != son[now])
			dfs2(v, v);
	}
	return;
}

ll ask_range(ll x, ll y) { // 询问链 
	ll sum = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]])
			swap(x, y);
		sum += ask(dfn[top[x]], dfn[x], 1);
		x = fa[top[x]];
	}
	return sum + ask(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], 1);
}

void update_range(ll x, ll y, ll k) { // 更新链 
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]])
			swap(x, y);
		add(dfn[top[x]], dfn[x], k, 1);
		x = fa[top[x]];
	}
	add(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], k, 1);
	return;
}

ll ask_son(ll x) { // 询问子树 
	return ask(dfn[x], dfn[x] + siz[x] - 1, 1);
}

void update_son(ll x, ll k) { // 更新子树 
	add(dfn[x], dfn[x] + siz[x] - 1, k, 1);
	return;
}

int main() {
	scanf("%lld%lld%lld%lld", &n, &m, &root, &p);
	for (ll i = 1; i <= n; i ++ )
		scanf("%lld", &a[i]);
	for (ll i = 1; i < n; i ++ ) {
		ll x, y;
		scanf("%lld%lld", &x, &y);
		g[x].push_back(y), g[y].push_back(x);
	}
	dfs1(root, 0);
	dfs2(root, root);
	build(1, n, 1);
	while (m -- ) {
		int op;
		cin >> op;
		if (op == 1) {
			ll x, y, k;
			scanf("%lld%lld%lld", &x, &y, &k);
			update_range(x, y, k);
		} else if (op == 2) {
			ll x, y;
			scanf("%lld%lld", &x, &y);
			printf("%lld\n", ask_range(x, y) % p);
		} else if (op == 3) {
			ll x, k;	
			scanf("%lld%lld", &x, &k);
			update_son(x, k);
		} else {
			ll x;
			scanf("%lld", &x);
			printf("%lld\n", ask_son(x) % p);
		}
	}
	return 0;
} 
2024/8/9 13:31
加载中...