[BZOJ4825][LCT]HNOI2017:单旋

BZOJ4825

我们可以用一个set维护一下点的大小关系,那么修改只需要查一下前驱后继就行了
然后旋转的话,推一下就可以发现只会影响 f a [ x ] fa[x] fa[x]的左/右儿子,和 r o o t root root的父亲,
那就随便LCT一波, d e p dep dep用LCT也很好维护

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1e5+5;
int a[N];
struct cmp{bool operator()(const int &x,const int &y)const{return a[x]<a[y];}};
set<int,cmp>s;
namespace LCT{
	int tot=0,root;
	int ls[N],rs[N],fa[N],rev[N],siz[N],L[N],R[N],F[N];
	inline void pushup(int x){siz[x]=siz[ls[x]]+siz[rs[x]]+1;}
	inline int isrs(int x){return x==rs[fa[x]];}
	inline bool isroot(int x){
		if(!fa[x]) return 1;
		return ls[fa[x]]!=x && rs[fa[x]]!=x;
	}
	inline void pushdown(int x){
		if(rev[x]){
			swap(ls[x],rs[x]);
			if(ls[x]) rev[ls[x]]^=1;
			if(rs[x]) rev[rs[x]]^=1;
			rev[x]=0;
		}
	}
	inline void rotate(int x){
		int y=fa[x],z=fa[y],b=(ls[y]==x?rs[x]:ls[x]);
		if(z && !isroot(y)) (ls[z]==y?ls[z]:rs[z])=x;
		fa[x]=z;fa[y]=x;b?fa[b]=y:0;
		if(ls[y]==x) rs[x]=y,ls[y]=b;
		else ls[x]=y,rs[y]=b;
		pushup(y);pushup(x);
	}
	int que[N];
	inline void splay(int x){
		que[que[0]=1]=x;
		for(int y=x;!isroot(y);y=fa[y]) que[++que[0]]=fa[y];
		for(int i=que[0];i;i--) pushdown(que[i]);
		while(!isroot(x)){
			if(!isroot(fa[x])){
				if(isrs(fa[x])==isrs(x)) rotate(fa[x]);
				else rotate(x);
			}
			rotate(x);
		}
		pushup(x); 
	}
	inline void access(int x){for(int y=0;x;y=x,x=fa[x]){splay(x);rs[x]=y;if(y) fa[y]=x;pushup(x);}}
	inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}
	inline void link(int x,int y){makeroot(x);fa[x]=y;}
	inline void cut(int x,int y){makeroot(x);access(y);splay(y);ls[y]=fa[x]=0;pushup(y);}
	inline int add(int x){
		a[++tot]=x;x=tot;
		set<int,cmp>::iterator it=s.insert(tot).first;
		if(!root) pushup(root=x);
		else{
			int f1=0,f2=0,d1=0,d2=0;
			if(it!=s.begin()) f1=*(--it),makeroot(root),access(f1),splay(f1),d1=siz[f1],++it;
			++it;
			if(it!=s.end()) f2=*it,makeroot(root),access(f2),splay(f2),d2=siz[f2];
			--it;
			if(d1>d2) R[f1]=x,F[x]=f1,pushup(x),link(f1,x);
			else L[f2]=x,F[x]=f2,pushup(x),link(f2,x);
		}
		makeroot(root);access(x);splay(x);
		return siz[x];
	}
	inline int getmn(int kd){
		int x=*s.begin(),y;
		int res;
		if(kd) s.erase(x);
		makeroot(root);access(x);splay(x);res=siz[x],y=R[x];
		if(x==root){if(kd && y) F[y]=0,cut(x,y),root=y;}
		else{
			cut(x,F[x]),L[F[y]]=y,pushup(x);
			if(y) cut(x,y),F[y]=F[x],L[F[y]]=y,link(y,F[x]);
			F[x]=0;
			if(!kd){
				splay(root),F[root]=x,R[x]=root,pushup(root);
				link(x,root);root=x;
			}
		}
		return res;
	}
	inline int getmx(int kd){
		int x=*s.rbegin(),y;
		int res;
		if(kd) s.erase(x);
		makeroot(root);access(x);splay(x);res=siz[x],y=L[x];
		if(x==root){if(kd && y) F[y]=0,cut(x,y),root=y;}
		else{
			cut(x,F[x]),R[F[y]]=y,pushup(x);
			if(y) cut(x,y),F[y]=F[x],R[F[y]]=y,link(y,F[x]);
			F[x]=0;
			if(!kd){
				splay(root),F[root]=x,L[x]=root,pushup(root);
				link(x,root);root=x;
			}
		}
		return res;
	}
}
int main(){
	int q=read();
	while(q--){
		int op=read();
		if(op==1) cout<<LCT::add(read())<<"\n";
		if(op==2) cout<<LCT::getmn(0)<<"\n";
		if(op==3) cout<<LCT::getmx(0)<<"\n";
		if(op==4) cout<<LCT::getmn(1)<<"\n";
		if(op==5) cout<<LCT::getmx(1)<<"\n";
	}
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值