Luogu-3979-bzoj-3083-遥远的国度

题目

https://www.luogu.org/problemnew/show/P3979

题意

给一棵带点权的树,要求支持路径上点权修改,查询以某一个点为根时,某个点的子树中最小的点权。

题解

  • 树链剖分 + 线段树
  • 设当前的根为 rt,当前查询的为 u
    • lca(rt, u) != rt 那么查询的结果就是 u 的子树
    • lca(rt, u) = rt 那么查询的是整棵树去掉一棵子树(u 的儿子中包含 rt 的那棵子树)。特别地,如果 rt = u 时查询的是整棵树。

代码

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
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
#ifdef zerol
#define dbg(args...) do { cout << "\033[32;1m" << #args << " -> "; err(args); } while (0)
#else
#define dbg(...)
#endif
void err() { cout << "\033[39;0m" << endl; }
template<template<typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args) { for (auto x: a) cout << x << ' '; err(args...); }
template<typename T, typename... Args>
void err(T a, Args... args) { cout << a << ' '; err(args...); }
// -----------------------------------------------------------------------------
const int maxn = 1E5 + 100, INF = 1E12;
vector<int> G[maxn];
LL w[maxn];
int n, Q;

namespace sg {
struct Q {
LL setv;
explicit Q(LL setv = -1): setv(setv) {}
void operator += (const Q& q) { if (q.setv != -1) setv = q.setv; }
};
struct P {
LL min;
explicit P(LL min = INF): min(min) {}
void up(Q& q) { if (q.setv != -1) min = q.setv; }
};
template<typename T>
P operator & (T&& a, T&& b) {
return P(min(a.min, b.min));
}
P p[maxn << 2];
Q q[maxn << 2];
#define lson o * 2, l, (l + r) / 2
#define rson o * 2 + 1, (l + r) / 2 + 1, r
void up(int o, int l, int r) {
if (l == r) p[o] = P();
else p[o] = p[o * 2] & p[o * 2 + 1];
p[o].up(q[o]);
}
void down(int o, int l, int r) {
q[o * 2] += q[o]; q[o * 2 + 1] += q[o];
q[o] = Q();
up(lson); up(rson);
}
template<typename T>
void build(T&& f, int o = 1, int l = 1, int r = n) {
if (l == r) q[o] = f(l);
else { build(f, lson); build(f, rson); }
up(o, l, r);
dbg(o, l, r, p[o].min, q[o].setv);
}
P query(int ql, int qr, int o = 1, int l = 1, int r = n) {
if (ql > r || l > qr) return P();
if (ql <= l && r <= qr) return p[o];
down(o, l, r);
return query(ql, qr, lson) & query(ql, qr, rson);
}
void update(int ql, int qr, const Q& v, int o = 1, int l = 1, int r = n) {
if (ql > r || l > qr) return;
if (ql <= l && r <= qr) q[o] += v;
else {
down(o, l, r);
update(ql, qr, v, lson); update(ql, qr, v, rson);
}
up(o, l, r);
}
}

const int SP = 18;
int fa[maxn], dep[maxn], idx[maxn], out[maxn], ridx[maxn], pa[maxn][SP];
namespace hlc {
int sz[maxn], son[maxn], top[maxn], clk;
void predfs(int u, int d) {
dep[u] = d; sz[u] = 1;
pa[u][0] = fa[u]; FOR (i, 1, SP) pa[u][i] = pa[pa[u][i - 1]][i - 1];
int& maxs = son[u] = -1;
for (int& v: G[u]) {
if (v == fa[u]) continue;
fa[v] = u;
predfs(v, d + 1);
sz[u] += sz[v];
if (maxs == -1 || sz[v] > sz[maxs]) maxs = v;
}
}
void dfs(int u, int tp) {
top[u] = tp; idx[u] = ++clk; ridx[clk] = u;
if (son[u] != -1) dfs(son[u], tp);
for (int& v: G[u])
if (v != fa[u] && v != son[u]) dfs(v, v);
out[u] = clk;
}
template<typename T>
int go(int u, int v, T&& f) {
int uu = top[u], vv = top[v];
while (uu != vv) {
if (dep[uu] < dep[vv]) { swap(uu, vv); swap(u, v); }
f(idx[uu], idx[u]);
u = fa[uu]; uu = top[u];
}
if (dep[u] < dep[v]) swap(u, v);
f(idx[v], idx[u]);
return v;
}
int up(int u, int v) {
int dd = dep[u] - dep[v] - 1;
FOR (i, 0, SP) if ((1 << i) & dd) u = pa[u][i];
return u;
}
}

int cap;
int main() {
#ifdef zerol
freopen("in", "r", stdin);
#endif
cin >> n >> Q;
FOR (_, 1, n) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v); G[v].push_back(u);
}
FOR (i, 1, n + 1) scanf("%lld", &w[i]);
fa[1] = 1; hlc::predfs(1, 0); hlc::dfs(1, 1);
sg::build([](int x)->sg::Q { return sg::Q(w[ridx[x]]); });

cin >> cap;

while (Q--) {
int tp; scanf("%d", &tp);
if (tp == 1) scanf("%d", &cap);
else if (tp == 2) {
int u, v; LL k; scanf("%d%d%lld", &u, &v, &k);
hlc::go(u, v, [&](int a, int b) { sg::update(a, b, sg::Q(k)); });
} else {
int x; scanf("%d", &x);
int lca = hlc::go(x, cap, [](int, int) {});
dbg(cap, x, lca);
if (x == cap) printf("%lld\n", sg::query(1, n).min);
else if (lca != x) printf("%lld\n", sg::query(idx[x], out[x]).min);
else {
int t = hlc::up(cap, x);
printf("%lld\n", (sg::query(1, idx[t] - 1) & sg::query(out[t] + 1, n)).min);
}
}
}
}