yaoxi-std 的博客

$\text{开}\mathop{\text{卷}}\limits^{ju\check{a}n}\text{有益}$

0%

P6329 【模版】点分树|震波

P6329 【模版】点分树|震波

题面

题目链接

解法

题目里都说了是点分树

发现自己学过的点分树现在已经不会写了,改天来补个点分树的题解吧。

AC代码

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/**
* @file: P6329.cpp
* @author: yaoxi-std
* @url: https://www.luogu.com.cn/problem/P6329
*/
// #pragma GCC optimize ("O2")
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define resetIO(x) \
freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define debug(fmt, ...) \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
template <class _Tp>
inline _Tp& read(_Tp &x) {
bool sign = false;
char ch = getchar();
long double tmp = 1;
for (; !isdigit(ch); ch = getchar())
sign |= (ch == '-');
for (x = 0; isdigit(ch); ch = getchar())
x = x * 10 + (ch ^ 48);
if (ch == '.')
for (ch = getchar(); isdigit(ch); ch = getchar())
tmp /= 10.0, x += tmp * (ch ^ 48);
return sign ? (x = -x) : x;
}
template <class _Tp>
inline void write(_Tp x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar((x % 10) ^ 48);
}
const int MAXN = 2e5 + 10;
const int LOGN = 20;
const int INFL = 0x3f3f3f3f3f3f3f3f;
struct binary_indexed_tree {
int n;
vector<int> c;
void init(int m) {
// ##sb-mistakes## 开`vector`当动态开点树状数组`resize`时没有$+1$
// c.resize(n = m);
c.resize((n = m) + 1);
}
void add(int x, int v) {
for (int i = x; i <= n; i += (i & -i))
c[i] += v;
}
int sum(int x) {
x = min(x, n);
int ret = 0;
for (int i = x; i; i -= (i & -i))
ret += c[i];
return ret;
}
};
int n, q, a[MAXN], fa[MAXN], dep[MAXN], fq[MAXN][LOGN];
int cur[MAXN], siz[MAXN], mxsiz[MAXN];
bitset<MAXN> vis;
vector<int> g[MAXN];
binary_indexed_tree bit[MAXN][2];
int getroot(int u, int f, int sz) {
siz[u] = 1;
mxsiz[u] = 0;
int ret = 0;
for (auto v : g[u]) {
if (v == f || vis[v])
continue;
int tmp = getroot(v, u, sz);
siz[u] += siz[v];
mxsiz[u] = max(mxsiz[u], siz[v]);
if (mxsiz[tmp] < mxsiz[ret])
ret = tmp;
}
mxsiz[u] = max(mxsiz[u], sz - siz[u]);
if (mxsiz[u] < mxsiz[ret])
ret = u;
return ret;
}
void build1(int u, int f, int sz) {
fa[u] = f, vis[u] = true;
bit[u][0].init(sz + 2);
bit[u][1].init(sz + 2);
for (auto v : g[u]) {
if (vis[v])
continue;
int nsz = (siz[u] > siz[v]) ? siz[v] : (sz - siz[u]);
int nrt = getroot(v, 0, nsz);
build1(nrt, u, nsz);
}
}
void build2(int u, int f) {
fq[u][0] = f, dep[u] = dep[f] + 1;
for (int i = 1; i < LOGN; ++i)
fq[u][i] = fq[fq[u][i - 1]][i - 1];
for (auto v : g[u])
if (v != f)
build2(v, u);
}
int lca(int u, int v) {
if (dep[u] < dep[v])
swap(u, v);
int t = dep[u] - dep[v];
for (int i = LOGN - 1; ~i; --i)
if ((t >> i) & 1)
u = fq[u][i];
if (u == v)
return u;
for (int i = LOGN - 1; ~i; --i)
if (fq[u][i] != fq[v][i])
u = fq[u][i], v = fq[v][i];
return fq[u][0];
}
int getdis(int x, int y) {
int l = lca(x, y);
return dep[x] + dep[y] - 2 * dep[l];
}
void modify(int x, int v) {
for (int u = x; u; u = fa[u]) {
bit[u][0].add(getdis(u, x) + 1, v - cur[x]);
if (fa[u])
bit[u][1].add(getdis(fa[u], x) + 1, v - cur[x]);
}
cur[x] = v;
}
int query(int x, int k) {
int ret = 0;
for (int u = x; u; u = fa[u]) {
int d = k - getdis(u, x);
if (d >= 0)
ret += bit[u][0].sum(d + 1);
if (fa[u]) {
d = k - getdis(fa[u], x);
if (d >= 0)
ret -= bit[u][1].sum(d + 1);
}
}
return ret;
}
signed main() {
read(n), read(q);
for (int i = 1; i <= n; ++i)
read(a[i]);
for (int i = 1; i < n; ++i) {
int u, v;
read(u), read(v);
g[u].push_back(v);
g[v].push_back(u);
}
mxsiz[0] = INFL;
build1(getroot(1, 0, n), 0, n);
build2(1, 0);
int tt = 0;
for (int i = 1; i <= n; ++i)
modify(i, a[i]);
while (q--) {
int op, x, y;
read(op), read(x), read(y);
x ^= tt, y ^= tt;
if (op == 0) {
write(tt = query(x, y));
putchar('\n');
} else {
modify(x, y);
}
}
return 0;
}