https://darkbzoj.tk/problem/2959
和那个bzoj4998 星球联盟比较像,都是用并查集加 lct 来维护双连通性
其实就是要处理环,因为如果无环,那么要求的值就是路径上所有点的值
而有了环,由于没有断边操作,那么就把整个环缩成一个点,用并查集来维护
还有一个并查集用来维护连通性(上一行说的是维护双连通性的)
更具体的,就是如果连边时给定两个点 ((x,y)),它们已经连通了,就在 lct 中把它们的链 split 出来,把这些点的权值都加到 (u,v) 的其中一个点上,维护双连通性的并查集父亲也指向那个点
这样由于 lct 中套了一个并查集,每次要把 lct 里的点 find 一下再进行操作
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define N 200005
struct tr{
tr *fa,*son[2];
int sum,val,tag;
tr *setfa;
}*null,dizhi[N],*pos[N];
int fa[N];
inline tr *find(tr *k){return (k->setfa==k)?k:k->setfa=find(k->setfa);}
inline int find(int k){return k==fa[k]?k:fa[k]=find(fa[k]);}
int val[N];
#define ident(tree,fa) (fa->son[1]==tree)
#define notroot(tree) (find(tree->fa)->son[0]==tree||find(tree->fa)->son[1]==tree)
#define pushup(tree) (tree->sum=tree->val+tree->son[0]->sum+tree->son[1]->sum)
inline void connect(tr *tree,tr *fa,int k){tree->fa=fa;fa->son[k]=tree;}
inline void pushdown(tr *tree){
if(!tree->tag) return;
tree->tag=0;
std::swap(tree->son[0],tree->son[1]);
tree->son[0]->tag^=1;tree->son[1]->tag^=1;
}
inline void rotate(tr *tree){
tr *fa=find(tree->fa),*faa=find(fa->fa);
pushdown(fa);pushdown(tree);
int k=ident(tree,fa);
connect(tree->son[k^1],fa,k);
tree->fa=faa;
if(notroot(fa)) faa->son[ident(fa,faa)]=tree;
connect(fa,tree,k^1);
pushup(fa);pushup(tree);
}
inline void splay(tr *tree){
reg tr *fa,*faa;
while(notroot(tree)){
fa=find(tree->fa);faa=find(fa->fa);
if(notroot(fa)) ident(fa,faa)^ident(tree,fa)?rotate(tree):rotate(fa);
rotate(tree);
}
}
inline void access(reg tr *x){
for(reg tr *lastx=null;x!=null;lastx=x,x=find(x->fa)){
pushdown(x);
splay(x);
x->son[1]=lastx;pushup(x);
}
}
inline void makeroot(tr *tree){
access(tree);
splay(tree);tree->tag^=1;
}
int ans;
void dfs(tr *x,tr *pre){
if(x==null) return;
if(x!=pre) x->setfa=pre;
pushdown(x);
dfs(x->son[0],pre);dfs(x->son[1],pre);
}
inline void link(tr *x,tr *y){
makeroot(x);
x->fa=y;
}
inline void Link(int uu,int vv){
tr *x=find(pos[uu]),*y=find(pos[vv]);
if(x==y) return;//已经双连通
if(find(uu)!=find(vv)){//未连通
link(x,y);
fa[fa[uu]]=fa[vv];
}
else{
makeroot(x);
access(y);splay(y);
y->val=y->sum;
dfs(y,y);
}
}
inline void change(tr *x,int k){
tr *findx=find(x);
splay(findx);
findx->val+=k;findx->sum+=k;
}
int main(){
// std::freopen("1.in","r",stdin);
// std::freopen("out","w",stdout);
int n=read(),m=read();
null=&dizhi[0];
null->setfa=null;
for(reg int i=1;i<=n;i++){
pos[i]=&dizhi[i];
dizhi[i].son[0]=dizhi[i].son[1]=dizhi[i].fa=null;
dizhi[i].sum=dizhi[i].val=val[i]=read();
dizhi[i].setfa=&dizhi[i];
fa[i]=i;
}
int uu,vv,op;
while(m--){
op=read();uu=read();vv=read();
if(op==1) Link(uu,vv);
else if(op==2) change(pos[uu],vv-val[uu]),val[uu]=vv;
else{
tr *x=find(pos[uu]),*y=find(pos[vv]);
if(find(uu)!=find(vv)) puts("-1");
else{
makeroot(x);
access(y);splay(y);
printf("%d
",y->sum);
}
}
}
return 0;
}