BZOJ2843: 极地旅行社【LCT+并查集】

2843: 极地旅行社

【题目描述】

传送门

【题解】

就是裸的LCT,只要维护Splay中节点的和就可以了,连通性可以用并查集判。

【代码如下】

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=30005;
int n,Q,a[MAXN],fa[MAXN];char ch[MAXN];
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
#include<cctype>
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
	return f?ret:-ret;
}
struct LCT{
	int Fa[MAXN],Son[MAXN][2],Sum[MAXN];bool rev[MAXN];
	bool IsRoot(int x){return Son[Fa[x]][0]!=x&&Son[Fa[x]][1]!=x;}
	bool GetSon(int x){return Son[Fa[x]][1]==x;}
	void PushUp(int x){Sum[x]=Sum[Son[x][0]]+Sum[Son[x][1]]+a[x];}
	void Rotate(int x){
		int fa=Fa[x],l=GetSon(x);
		if(!IsRoot(fa)) Son[Fa[fa]][GetSon(fa)]=x;
		Son[fa][l]=Son[x][l^1],Fa[x]=Fa[fa],Fa[Son[x][l^1]]=fa,Son[x][l^1]=fa;Fa[fa]=x;
		PushUp(fa),PushUp(x); 
	}
	void PushDown(int x){if(!rev[x]) return;rev[x]^=1,rev[Son[x][0]]^=1,rev[Son[x][1]]^=1,swap(Son[x][0],Son[x][1]);}
	void DFS(int x){if(!IsRoot(x)) DFS(Fa[x]);PushDown(x);}
	void Splay(int x){for(DFS(x);!IsRoot(x);Rotate(x)) if(!IsRoot(Fa[x])) (GetSon(Fa[x])==GetSon(x))?Rotate(Fa[x]):Rotate(x);}
	void Access(int x){for(int lst=0;x;lst=x,x=Fa[x]) Splay(x),Son[x][1]=lst,PushUp(x);}
	void MakeRoot(int x){Access(x),Splay(x),rev[x]^=1;}
	int Link(int x,int y){if(get(y)==get(x)) return 0;MakeRoot(x),Fa[x]=y,fa[get(y)]=get(x);return 1;}
	void Split(int x,int y){MakeRoot(x),Access(y),Splay(x);}
	int Ask(int x,int y){if(get(y)!=get(x)) return -1;Split(x,y);return Sum[x];}
}T;
int main(){
	n=read();for(int i=1;i<=n;i++) a[i]=read(),fa[i]=i;
	Q=read();
	while(Q--){
		scanf("%s",ch);int A=read(),B=read();
		if(ch[0]=='b'){int t=T.Link(A,B);printf(t?"yes\n":"no\n");}else
		if(ch[0]=='p') T.Access(A),T.Splay(A),a[A]=B,T.PushUp(A);
		else{int t=T.Ask(A,B);printf(t==-1?"impossible\n":"%d\n",t);}
	}
	return 0;
} 
posted @ 2019-03-12 16:27  XSamsara  阅读(125)  评论(0编辑  收藏  举报