Luogu P3384 【模板】轻重链剖分

题目描述

https://www.luogu.com.cn/problem/P3384

树懒剖分模板题

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 100010
#define ll long long
using namespace std;

int n, m, p, rt, a[maxn];

struct Edge {
int to, next;
} e[maxn * 2]; int c1, head[maxn];
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

int dep[maxn], son[maxn], sz[maxn], f[maxn];
void dfs(int u, int fa) {
int Max = 0; sz[u] = 1;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa) continue;
f[v] = u; dep[v] = dep[u] + 1;
dfs(v, u); sz[u] += sz[v];
if (sz[v] > Max) Max = sz[v], son[u] = v;
}
}

int top[maxn], id[maxn], c2, bl[maxn];
void dfs(int u, int fa, int topf) {
top[u] = topf; id[u] = ++c2; bl[c2] = u;
if (son[u]) dfs(son[u], u, topf);
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa || v == son[u]) continue;
dfs(v, u, v);
}
}

#define lc i << 1
#define rc i << 1 | 1
struct Seg {
ll v, add;
} T[maxn * 4];
void build(int i, int l, int r) {
if (l == r) return (void) (T[i].v = a[bl[l]]);
int m = l + r >> 1;
build(lc, l, m); build(rc, m + 1, r);
T[i].v = (T[lc].v + T[rc].v) % p;
}

void update(int i, int l, int r, int L, int R, ll v) {
if (l > R || r < L) return ;
T[i].v = (T[i].v + v * (min(R, r) - max(L, l) + 1)) % p;
if (L <= l && r <= R) return (void) (T[i].add = (T[i].add + v) % p);
int m = l + r >> 1;
update(lc, l, m, L, R, v); update(rc, m + 1, r, L, R, v);
}

ll query(int i, int l, int r, int L, int R, ll add) {
if (l > R || r < L) return 0;
if (L <= l && r <= R) return (T[i].v + add * (r - l + 1)) % p;
int m = l + r >> 1;
return (query(lc, l, m, L, R, (add + T[i].add) % p) + query(rc, m + 1, r, L, R, (add + T[i].add) % p)) % p;
}

inline void solve_1() {
int x, y, z; scanf("%d%d%d", &x, &y, &z);
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, id[top[x]], id[x], z);
x = f[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
update(1, 1, n, id[x], id[y], z);
}

inline void solve_2() {
int x, y; ll s = 0; scanf("%d%d", &x, &y);
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
s = (s + query(1, 1, n, id[top[x]], id[x], 0)) % p;
x = f[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
s = (s + query(1, 1, n, id[x], id[y], 0)) % p;
printf("%lld\n", s);
}

inline void solve_3() {
int x, y; scanf("%d%d", &x, &y);
update(1, 1, n, id[x], id[x] + sz[x] - 1, y);
}

inline void solve_4() {
int x; scanf("%d", &x);
printf("%lld\n", query(1, 1, n, id[x], id[x] + sz[x] - 1, 0));
}


int main() { memset(head, -1, sizeof head);
cin >> n >> m >> rt >> p;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i < n; ++i) {
int x, y; scanf("%d%d", &x, &y);
add_edge(x, y); add_edge(y, x);
}
dep[rt] = 1; dfs(rt, 0); dfs(rt, 0, rt); build(1, 1, n);
for (int i = 1; i <= m; ++i) {
int opt; scanf("%d", &opt);
switch (opt) {
case 1 : solve_1(); break;
case 2 : solve_2(); break;
case 3 : solve_3(); break;
case 4 : solve_4(); break;
}
}
return 0;
}