#LCT,并查集#洛谷 10658 BZOJ2959 长跑

题目传送门


分析

考虑用两个并查集来维护,第一个并查集维护连通性,而第二个并查集维护边双连通分量,也就是如果两个点位于不同的边双就把它们合到一起,

查询就是缩点后两点路径点权之和,可以用 LCT 维护,注意父亲变成了边双上的父亲而不是原树上的父亲。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=150101; int n,m,a[N],f[N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
struct Union_Set{
	int f[N],w[N];
    int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
}T;
struct Splay{
	int w[N],son[N][2],fat[N],stac[N],TOP; bool rev[N];
	bool unroot(int x){return son[T.getf(fat[x])][0]==x||son[T.getf(fat[x])][1]==x;}
	bool Is_R(int x){return son[T.getf(fat[x])][1]==x;}
	void pup(int x){w[x]=w[son[x][0]]+w[son[x][1]]+T.w[x];}
	void Rev(int x){swap(son[x][0],son[x][1]),rev[x]^=1;}
	void pdown(int x){
		if (rev[x]){
			if (son[x][0]) Rev(son[x][0]);
			if (son[x][1]) Rev(son[x][1]);
			rev[x]=0;
		}
	}
	void rotate(int x){
    	int Fa=T.getf(fat[x]),FFa=T.getf(fat[Fa]),wh=Is_R(x),t=son[x][wh^1];
    	if (unroot(Fa)) son[FFa][Is_R(Fa)]=x;
    	son[x][wh^1]=Fa,son[Fa][wh]=t;
    	if (t) fat[t]=Fa;
		fat[Fa]=x,fat[x]=FFa;
    	pup(Fa),pup(x);
	}
	void splay(int x){
		int y=x; stac[TOP=1]=y;
		while (unroot(y)) stac[++TOP]=y=T.getf(fat[y]);
		for (;TOP;--TOP) pdown(stac[TOP]);
		for (;unroot(x);rotate(x)){
			int Fa=T.getf(fat[x]);
			if (unroot(Fa)) rotate((Is_R(x)^Is_R(Fa))?x:Fa);
		}
	}
	void Access(int x){
		for (int y=0;x;x=T.getf(fat[y=x]))
			splay(x),son[x][1]=y,pup(x);
	}
	void Make_root(int x){Access(x),splay(x),Rev(x);}
	int Find_root(int x){
		Access(x),splay(x);
		for (;son[x][0];x=son[x][0]) pdown(x);
		splay(x);
		return x;
	}
	void Split(int x,int y){Make_root(x),Access(y),splay(y);}
	void Link(int x,int y){Make_root(x); if (Find_root(y)!=x) fat[x]=y;}
}Tre;
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
void Merge(int rt,int x){
	if (T.getf(rt)!=T.getf(x)){
		T.w[T.getf(rt)]+=T.w[T.getf(x)];
		T.f[T.getf(x)]=T.f[T.getf(rt)];
	}
	if (Tre.son[x][0]) Merge(rt,Tre.son[x][0]);
	if (Tre.son[x][1]) Merge(rt,Tre.son[x][1]);
}
int main(){
	n=iut(); m=iut();
	for (int i=1;i<=n;++i) T.w[i]=a[i]=iut(),T.f[i]=f[i]=i;
	while (m--){
	    int opt=iut(),x=iut(),y=iut();
		switch (opt){
			case 1:{
				x=T.getf(x),y=T.getf(y);
				if (getf(x)!=getf(y)){
					f[getf(x)]=getf(y);
					Tre.Link(x,y);
				}else if (x!=y){
					Tre.Split(x,y);
					Merge(y,y);
					Tre.pup(y);
				}
				break;
			}
			case 2:{
				int u=T.getf(x);
				Tre.Make_root(u);
				T.w[u]+=y-a[x],a[x]=y;
				Tre.pup(u);
				break;
			}
			case 3:{
				x=T.getf(x),y=T.getf(y);
				if (getf(x)!=getf(y)) putchar('-'),putchar(49);
				    else Tre.Split(x,y),print(Tre.w[y]);
				putchar(10);
				break;
			} 
		}
	}
	return 0;
}
posted @ 2025-06-24 03:47  lemondinosaur  阅读(9)  评论(0)    收藏  举报