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;
} 

转载于:https://www.cnblogs.com/XSamsara/p/10547923.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值