题意

每个点有各自的权值,要求维护操作:动态加边、动态修改权值、询问在每个点只能经过一次的情况下两点间路程中的最大权值和

题解

首先对于一个静态的图,将其缩点,可以得到一棵树,那么两点间询问的答案即为它们之间经过的 $BCC$ 的权值和

支持动态加边,就需要用到 $LCT$ 去维护 $BCC$

如果两个点所在 $BCC$ 在不同树上,那么直接连边即可;反之,则说明形成了环,就暴力将这条链拖出来,用选定一个标准节点,用并查集将链上其它节点连到标准节点上,容易证明,这样的复杂度是均摊 $O (\log n)$ 的

查询即修改容易实现,不加赘述

注意,此题没有删边,所以 $findroot$ 可用另一个并查集代替,不然会 $T$

代码

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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>

using namespace std;

typedef long long LL;

const int MAXN = 15e04 + 10;

int ances[MAXN];
int find (int p) {
return p == ances[p] ? p : ances[p] = find (ances[p]);
}
int lctanc[MAXN];
int lctfind (int p) {
return p == lctanc[p] ? p : lctanc[p] = lctfind (lctanc[p]);
}

LL realval[MAXN];
int father[MAXN]= {0};
int son[MAXN][2]= {0};
LL Sum[MAXN]= {0}, value[MAXN]= {0};
int revtag[MAXN]= {0};

int isroot (int p) {
return son[father[p]][0] != p && son[father[p]][1] != p;
}
int sonbel (int p) {
return son[father[p]][1] == p;
}
void reverse (int p) {
if (! p)
return ;
swap (son[p][0], son[p][1]);
revtag[p] ^= 1;
}
void pushup (int p) {
Sum[p] = Sum[son[p][0]] + Sum[son[p][1]] + value[p];
}
void pushdown (int p) {
if (revtag[p]) {
reverse (son[p][0]), reverse (son[p][1]);
revtag[p] = 0;
}
}
void rotate (int p) {
int fa = father[p], anc = father[fa];
int s = sonbel (p);
son[fa][s] = son[p][s ^ 1];
if (son[fa][s])
father[son[fa][s]] = fa;
if (! isroot (fa))
son[anc][sonbel (fa)] = p;
father[p] = anc;
son[p][s ^ 1] = fa, father[fa] = p;
pushup (fa), pushup (p);
}
int Stack[MAXN];
int top = 0;
void splay (int p) {
top = 0, Stack[++ top] = p;
for (int nd = p; ! isroot (nd); nd = father[nd])
Stack[++ top] = father[nd];
while (top > 0)
pushdown (Stack[top]), top --;
for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
if (! isroot (fa))
sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
}
void Access (int p) {
for (int tp = 0; p; tp = p, p = father[tp] = find (father[p])) // 注意因为有并查集,所以也要同时更新father[tp]
splay (p), son[p][1] = tp, pushup (p);
}
void Makeroot (int p) {
Access (p), splay (p), reverse (p);
}
void Split (int x, int y) {
Makeroot (x);
Access (y), splay (y);
}
void link (int x, int y) {
Makeroot (x);
father[x] = y;
int fx = lctfind (x), fy = lctfind (y);
lctanc[fx] = fy;
}

void merge (int p, int root) { // 暴力合并
if (! p)
return ;
if (p != root)
ances[p] = root, value[root] += value[p];
merge (son[p][0], root), merge (son[p][1], root);
}
void Add (int x, int y) {
int fx = find (x), fy = find (y);
if (fx == fy)
return ;
if (lctfind (fx) != lctfind (fy)) {
link (fx, fy);
return ;
}
Split (fx, fy);
merge (fy, fy);
son[fy][0] = son[fy][1] = 0;
pushup (fy);
}
void Modify (int x, int val) {
int fx = find (x);
splay (fx);
value[fx] -= realval[x] - val, realval[x] = val;
pushup (fx);
}
LL Query (int x, int y) {
int fx = find (x), fy = find (y);
if (lctfind (fx) != lctfind (fy))
return - 1;
Split (fx, fy);
return Sum[fy];
}

int N, M;

int getnum () {
int num = 0;
char ch = getchar ();
int isneg = 0;

while (! isdigit (ch)) {
if (ch == '-')
isneg = 1;
ch = getchar ();
}
while (isdigit (ch))
num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();

return isneg ? - num : num;
}

int answer[MAXN];
int cnt = 0;
int main () {
int N = getnum (), M = getnum ();
for (int i = 1; i <= N; i ++)
Sum[i] = value[i] = realval[i] = getnum (), lctanc[i] = ances[i] = i;
for (int i = 1; i <= M; i ++) {
int type = getnum ();
int x = getnum (), y = getnum ();
if (type == 1)
Add (x, y);
else if (type == 2)
Modify (x, y);
else if (type == 3)
printf ("%lld\n", Query (x, y));
}

return 0;
}

/*
9 31
10 20 30 40 50 60 70 80 90
3 1 2
1 1 3
1 1 2
1 8 9
1 2 4
1 2 5
1 4 6
1 4 7
3 1 8
3 8 8
1 8 9
3 8 8
3 7 5
3 7 3
1 4 1
3 7 5
3 7 3
1 5 7
3 6 5
3 3 6
1 2 4
1 5 5
3 3 6
2 8 180
3 8 8
2 9 190
3 9 9
2 5 150
3 3 6
2 1 210
3 3 6
*/