【模板】伸展树Splay(指针实现)

参考题目:LOJ107


解析:

联赛后统一更所有模板题解析。
数组版本的代码在这里


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
int getint(){
	re int num;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))f^=c=='-';num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return f?-num:num;
}

inline
void outint(int a){
	static char ch[13];
	if(a==0)pc('0');
	if(a<0)pc('-'),a=-a;
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

typedef struct splay_node *point;
struct splay_node{
	point son[2],fa;
	int val,cnt,siz;
	splay_node(int _val=0){
		son[0]=son[1]=NULL;
		fa=NULL;
		val=_val;
		siz=cnt=1;
	}
	
	point &lc(){return son[0];}
	point &rc(){return son[1];}
	bool which(){return fa->rc()==this;}
	void update(){
		siz=(son[0]?son[0]->siz:0)+(son[1]?son[1]->siz:0)+cnt;
	}
	void init(){
		lc()=rc()=fa=NULL;
		siz=cnt=1;
	}
	void clear(){
		lc()=rc()=fa=NULL;
		val=siz=cnt=0;
	}
};

struct SPLAY{
	point root;
	SPLAY():root(NULL){}
	
	void Rotate(point now){
		point Fa=now->fa;
		bool pos=!now->which();
		Fa->son[!pos]=now->son[pos];
		if(now->son[pos])now->son[pos]->fa=Fa;
		if(now->fa=Fa->fa)now->fa->son[Fa->which()]=now;
		Fa->fa=now;
		now->son[pos]=Fa;
		Fa->update();
		now->update();
		if(now->fa==NULL)root=now;
	}
	
	void Splay(point now,point to=NULL){
		for(point Fa=now->fa;(Fa=now->fa)!=to;Rotate(now))
		if(Fa->fa!=to)Rotate(now->which()==Fa->which()?Fa:now);
	}
	
	void Insert(cs int &key){
		if(!root){
			root=(point)malloc(sizeof(splay_node));
			root->init();
			root->val=key;
			return ;
		}
		point now=root,Fa;
		for(;;Fa=now,now=now->son[key>now->val]){
			if(now==NULL){
				now=(point)malloc(sizeof(splay_node));
				now->init();
				now->fa=Fa;
				now->val=key;
				Fa->son[key>Fa->val]=now;
				return Splay(now);
			}
			if(now->val==key){
				++now->cnt;
				Splay(now);
				return ;
			}
		}
	}
	
	point find(cs int &key){
		point now=root;
		while(now!=NULL&&now->val!=key)now=now->son[key>now->val];
		if(now!=NULL)Splay(now);
		return now;
	}
	
	point pre_pos(cs int &key){
		point now=find(key);
		re bool flag=false;
		if(now==NULL){
			Insert(key);
			now=root;
			flag=true;
		}
		if(now->lc()==NULL){
			if(flag)Delete(key);
			return NULL;
		}
		for(now=now->son[0];now->son[1];now=now->son[1]);
		if(flag)Delete(key);
		return now;
	}
	
	void Delete(cs int &key){
		point now=find(key);
		if(now==NULL)return ;
		if(now->cnt>1){
			--now->cnt;
			--now->siz;
			return ;
		}
		if(now->lc()==NULL&&now->rc()==NULL){
			free(now);
			root=NULL;
			return ;
		}
		if(now->lc()==NULL){
			root=now->rc();
			now->rc()->fa=NULL;
			free(now);
			return ;
		}
		if(now->rc()==NULL){
			root=now->lc();
			now->lc()->fa=NULL;
			free(now);
			return ;
		}
		point res_pre=pre_pos(now->val);
		point res=root;
		Splay(res_pre);
		
		root->rc()=res->rc();
		res->rc()->fa=root;
		root->update();
	}
	
	int querykth(int key){
		re int ans=0;
		re int res;
		point now=root;
		while(true){
			if(now->lc()&&key<=now->lc()->siz){
				now=now->lc();
				continue;
			}
			res=(now->lc()?now->lc()->siz:0)+now->cnt;
			if(key<=res)return now->val;
			key-=res;
			now=now->rc();
		}
	}
	
	int queryrank(cs int &key){
		point now=find(key);
		re bool flag=false;
		if(now==NULL){
			Insert(key);
			flag=true;
		}
		int ans=root->siz;
		if(root->rc())ans-=root->rc()->siz;
		ans-=root->cnt;
		if(flag)Delete(key);
		return ans;
	}
	
	int querypre(cs int &key){
		point now=find(key);
		bool flag=false;
		if(now==NULL){
			Insert(key);
			now=root;
			flag=true;
		}
		if(now->lc()==NULL){
			if(flag)Delete(key);
			return -1;
		}
		for(now=now->lc();now->rc();now=now->rc());
		if(flag)Delete(key);
		return now->val;
	}
	
	int querysuf(cs int &key){
		point now=find(key);
		bool flag=false;
		if(now==NULL){
			Insert(key);
			now=root;
			flag=true;
		}
		if(now->rc()==NULL){
			if(flag)Delete(key);
			return -1;
		}
		for(now=now->rc();now->lc();now=now->lc());
		if(flag)Delete(key);
		return now->val;
	}
	
}splay;

int n;
signed main(){
	n=getint();
	while(n--){
		int op=getint(),x=getint();
		switch(op){
			case 0:{splay.Insert(x);break;}
			case 1:{splay.Delete(x);break;}
			case 2:{outint(splay.querykth(x)),pc('\n');break;}
			case 3:{outint(splay.queryrank(x)),pc('\n');break;}
			case 4:{outint(splay.querypre(x)),pc('\n');break;}
			case 5:{outint(splay.querysuf(x)),pc('\n');break;}
		}
	}
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值