链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2959
三种操作,
修建一条路,
修改点的权值,
从a走到b的权值和.
我们用 LCT来做.
首先我们用LCT来动态加边,
如果两个点不连接,那么我们直接连上就可以了,
如果两个点已经连接了,那么我们有 access 这条路径,splay 一下, 然后把路径上的点的权值加到一个点上,这个用并查集维护.
也就是说 splay 中的所有点都会指向一个代表节点. 然后把代表节点的左右儿子清空, 所有节点的父亲我们会在以后的 access中更新.
然后我们用LCT的维护连通性会超时, 所以我们还要在开一个 并查集,这个并查集维护连通性.
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 100;
int a[N],b[N],g[N],ff[N];
int find(int k){
return g[k] == k ? k : g[k] = find(g[k]);
}
int findf(int k){
return ff[k] == k ? k : ff[k] = findf(ff[k]);
}
void unin(int x, int y){
int xx = findf(x), yy =findf(y);
if (xx != yy) ff[xx] = yy;
}
namespace LCT{
int f[N], sum[N], val[N], rev[N], hep[N], ch[N][2];
inline int isroot(int x) {
return ch[f[x]][0] != x && ch[f[x]][1] != x;
}
inline void pushup(int x) {
sum[x] = sum[ch[x][1]] + sum[ch[x][0]] + val[x];
}
inline void filp(int x) {
swap(ch[x][0], ch[x][1]);
rev[x] ^= 1; //标记表示已经翻转了该点的左右儿子
}
inline void pushdown(int x){
if (rev[x]){
if (ch[x][0]) filp(ch[x][0]);
if (ch[x][1]) filp(ch[x][1]);
rev[x] ^= 1;
}
}
inline void rotate(int x){
int y = f[x], z = f[y], k = ch[y][1] == x, v = ch[x][!k];
if (!isroot(y)) ch[z][ch[z][1] == y] = x;//Attention if()
ch[x][!k] = y; ch[y][k] = v;
if (v) f[v] = y;
f[y] = x, f[x] = z;
pushup(y); pushup(x);
}
inline void splay(int x){
int y = x, top = 0; hep[++top] = y;
while(!isroot(y)) hep[++top] = y = f[y]; //这里个splay 不同之处,用一个栈存下来节点.
while(top) pushdown(hep[top--]); //然后一个一个的从上往下pushdown .
while(!isroot(x)){
y = f[x]; top = f[y];
if (!isroot(y))
rotate((ch[y][0] == y) ^ (ch[top][0] == y)?x:y);
rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int y = 0; x; y = x, f[x] = find(f[x]), x = f[x])
splay(x), ch[x][1] = y, pushup(x);
}
inline void makeroot(int x){ //函数功能:把x拎成原图的根
access(x); splay(x); filp(x);
}
inline void dfs(int u, int fa){
g[u] = fa;
if (ch[u][0]) dfs(ch[u][0],fa);
if (ch[u][1]) dfs(ch[u][1],fa);
}
inline void link(int x,int y){
if (findf(x) == findf(y)){
makeroot(x); access(y); splay(y);
dfs(y,y);
val[y] = sum[y];
ch[y][0] = ch[y][1] = 0;
return;
}
makeroot(x); access(y); splay(y);
f[x] = y;
}
};
int n,m,x,y,op;
int main() {
int xx,yy;
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; ++i) {
scanf("%d",&LCT::val[i]),a[i] = LCT::val[i],g[i] = i,ff[i] = i;
LCT::sum[i] = a[i];
}
for (int i = 1; i <= m; ++i){
scanf("%d%d%d",&op,&x,&y);
if (op == 1){
xx = find(x); yy = find(y);
LCT::link(xx,yy);
unin(xx,yy);
} else if (op == 2){
int tmp = y - a[x];
a[x] = y; xx = find(x);
LCT::splay(xx);
LCT::val[xx] += tmp;
LCT::sum[xx] += tmp;
} else {
xx = find(x); yy = find(y);
if (findf(xx) != findf(yy)){
puts("-1");
} else{
LCT::makeroot(xx);
LCT::access(yy);
LCT::splay(yy);
printf("%d\n",LCT::sum[yy]);
}
}
}
return 0;
}