用LCT+并查集缩点,记两个并查集,一个是实际在树中的编号,一个是普通的并查集
注意:access中要更新father的编号,修改点值要把点splay上去再修改
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 160100
using namespace std;
int sum[maxn],fa[maxn],tag[maxn],ch[maxn][2],val[maxn],key[maxn],n,m,f[maxn];
struct ufs{
int f[maxn];
void init(){for(int i=1;i<=n;++i)f[i]=i;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void uni(int x,int y){f[find(x)]=find(y);}
}real,check;
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
void pushdown(int x){
if(!tag[x])return ;
tag[x]=0;
if(ch[x][0])tag[ch[x][0]]^=1;
if(ch[x][1])tag[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
}
void update(int x){
if(!x)return ;
sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+val[x]);
}
bool notroot(int x){
return (ch[fa[x]][0]==x||ch[fa[x]][1]==x);
}
void rotate(int p){
int q=fa[p],y=fa[q],k=(ch[q][1]==p);
if(y&¬root(q))ch[y][ch[y][1]==q]=p;
fa[ch[q][k]=ch[p][k^1]]=q;
fa[ch[p][k^1]=q]=p;
fa[p]=y;
update(q),update(p);
}
void splay(int x){
int y=0;
while(notroot(x)){
if(notroot(y=fa[x]))pushdown(fa[y]);
pushdown(y);pushdown(x);
if(notroot(y)){
if((ch[fa[x]][1]==x)^(ch[fa[y]][1]==y))rotate(x);
else rotate(y);
}
rotate(x);
}
pushdown(x);
update(x);
}
void access(int x){
for(int y=0;x;y=x,x=fa[x]=real.find(fa[x])){
splay(x);
ch[x][1]=y;
fa[y]=x;
update(x);
}
}
void rever(int u){
access(u),splay(u);
tag[u]^=1,pushdown(u);
}
void cut(int u,int v){
rever(u);access(v);splay(v);
fa[u]=ch[v][0]=0;
}
void link(int u,int v){
rever(u);access(v);splay(v);
fa[v]=u,ch[u][0]=v;
}
void dfs(int& u,int d){
if(!u)return ;
// printf("[%d]",u);
real.uni(u,d);
val[d]+=val[u];
dfs(ch[u][0],d);
dfs(ch[u][1],d);
u=0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&key[i]);
for(int i=1;i<=n;++i)val[i]=key[i];
real.init(),check.init();
for(int i=1;i<=m;++i){
int op,u,v,d;
scanf("%d%d%d",&op,&u,&v);
if(op==1){
u=real.find(u),v=real.find(v);
if(u==v)continue;
if(check.find(u)!=check.find(v)){
link(u,v),check.uni(u,v);
} else {
// printf("[%d,%d]",u,v);
rever(u),access(v),splay(v);
dfs(ch[v][0],v);
// printf("[%d]",val[v]);
update(v);
}
} else if(op==2){
d=real.find(u);
splay(d);
val[d]+=v-key[u],key[u]=v;
update(d);
} else {
if(check.find(u)!=check.find(v)){
printf("-1\n");continue;
}
u=real.find(u),v=real.find(v);
rever(u);access(v);splay(v);
printf("%d\n",sum[ch[v][0]]+val[v]);
}
}
}