巧妙的转化.

Description

有若干次路径标记/撤销操作.

每次询问一个位置, 没有经过这个这个位置的路径标记最大值.

Solution

每个节点维护一个堆, 为完全没有经过这个区间的路径标记最大值.

堆要惰性删除, 不过有奇技淫巧(通过特殊手段避免MLE).

每次更新, 去区间的补集在线段树上做就可以了.

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
#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;

const int maxn = 1e+5 + 1;

struct edge {
int to, nxt;
}e[maxn << 1];
int n, ptr, m, lnk[maxn];
int dfn[maxn], top[maxn], siz[maxn], mxson[maxn];
int dep[maxn], fa[maxn], cnt, ans, tot;
int val[maxn << 1], xx[maxn << 1], yy[maxn << 1], vpr;
pii arr[maxn];
struct Heap {
priority_queue<int> a, d;
inline void ps(int x) {
a.push(x);
}
inline void de(int x) {
d.push(x);
}
inline int tp() {
while (!d.empty() && a.top() == d.top()) a.pop(), d.pop();
return a.empty() ? -1 : a.top();
}
}s[maxn << 2];

void dfs(int x, int f) {
dep[x] = dep[f] + 1;
siz[x] = 1;
fa[x] = f;
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (y == f) continue;
dfs(y, x);
siz[x] += siz[y];
if (siz[y] >= siz[mxson[x]]) mxson[x] = y;
}
}
void dfs2(int x, int init) {
top[x] = init;
dfn[x] = ++cnt;
if (!mxson[x]) return;
dfs2(mxson[x], init);
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (y == fa[x] || y == mxson[x]) continue;
dfs2(y, y);
}
}
void update(int cur, int l, int r, int L, int R, int v, int t) {
if (l == L && r == R) {
if (t) s[cur].ps(v);
else s[cur].de(v);
return;
}
int mid = (l + r) >> 1;
if (R <= mid) update(cur << 1, l, mid, L, R, v, t);
else if (L > mid) update(cur << 1|1, mid + 1, r, L, R, v, t);
else {
update(cur << 1, l, mid, L, mid, v, t);
update(cur << 1|1, mid + 1, r, mid + 1, R, v, t);
}
}
void query(int cur, int l, int r, int p) {
ans = max(ans, s[cur].tp());
if (l == r) return;
int mid = (l + r) >> 1;
if (p <= mid) query(cur << 1, l, mid, p);
else query(cur << 1|1, mid + 1, r, p);
}
void modify(int x, int y, int v, int t) {
tot = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
arr[++tot] = make_pair(dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
arr[++tot] = make_pair(dfn[x], dfn[y]);
sort(arr + 1, arr + 1 + tot);
arr[0] = make_pair(0, 0); arr[tot + 1] = make_pair(n + 1, n + 1);
for (int i = 0; i <= tot; ++i) {
int l = arr[i].second + 1, r = arr[i + 1].first - 1;
if (l <= r)
update(1, 1, n, l, r, v, t);
}
}
inline void add(int bgn, int end) {
e[++ptr] = (edge){end, lnk[bgn]};
lnk[bgn] = ptr;
}
inline int rd() {
register int x = 0, c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return x;
}

int main() {
n = rd(); m = rd();
int u, v;
for (int i = 1; i < n; ++i) {
u = rd(); v = rd();
add(u, v);
add(v, u);
}
dfs(1, 0);
dfs2(1, 1);
int opt, vle;
while (m--) {
vpr++;
opt = rd();
if (opt == 0) {
u = rd(); v = rd(); vle = rd();
val[vpr] = vle;
xx[vpr] = u; yy[vpr] = v;
modify(u, v, vle, 1);
} else if (opt == 1) {
u = rd();
modify(xx[u], yy[u], val[u], 0);
} else {
u = rd(); ans = -1;
query(1, 1, n, dfn[u]);
printf("%d\n", ans);
}
}
return 0;
}