Splay 板子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
inline int read(){
   int s=0,w=1;
   char ch=getchar();	
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}

const int N=2e5+5;
struct node{
	int s[2],p,v;
	int size,cnt;
	void init(int _p,int _v){
		p=_p, v=_v;
		size=cnt=1;
	}
}tr[N];
int idx,root;

void pushup(int u){
	tr[u].size=tr[tr[u].s[0]].size+tr[tr[u].s[1]].size+tr[u].cnt;
}

void rotate(int x){
	int y=tr[x].p, z=tr[y].p;
	int k=tr[y].s[1]==x;
	tr[z].s[tr[z].s[1]==y]=x, tr[x].p=z;
	tr[tr[x].s[k^1]].p=y, tr[y].s[k]=tr[x].s[k^1];
	tr[y].p=x, tr[x].s[k^1]=y;
	pushup(y), pushup(x);
}

void splay(int x,int k){
	while(tr[x].p!=k){
		int y=tr[x].p, z=tr[y].p;
		if(z!=k)
			if((tr[z].s[1]==y) ^ (tr[y].s[1]==x)) rotate(x);
			else rotate(y);
		rotate(x);
	}
	if(k==0) root=x;
}

void insert(int v){
	int u=root, p=0;
	while(u && tr[u].v!=v) p=u, u=tr[u].s[v>tr[u].v];
	if(u) tr[u].cnt++, tr[u].size++;
	else{
		u=++idx;
		if(p) tr[p].s[v>tr[p].v]=u;
		tr[u].init(p,v); // update the msg of the new node
	}
	splay(u,0);
}

void find(int v){
	int u=root;
	if(!u) return;
	while(v!=tr[u].v && tr[u].s[v>tr[u].v]) u=tr[u].s[v>tr[u].v];
	splay(u,0);
}

int pre(int v){
	find(v);
	int u=root;
	if(tr[u].v<v) return u; // 如果树中所有数的值都没有 v 大,那么 v 的前驱一定是 u 
	u=tr[u].s[0];
	while(tr[u].s[1]) u=tr[u].s[1];
	return u;
}

int suf(int v){
	find(v);
	int u=root;
	if(tr[u].v>v) return u; // 如果树中所有数的值都没有 v 小,那么 v 的后继一定是 u 
	u=tr[u].s[1];
	while(tr[u].s[0]) u=tr[u].s[0];
	return u;
}

void remove(int v){
	int pu=pre(v), su=suf(v);
	splay(pu,0);splay(su,pu);
	int u=tr[su].s[0]; // the point to remove;
	if(tr[u].cnt>1) tr[u].cnt--, splay(u,0);
	else tr[su].s[0]=0;
}

int rk_for_num(int k){
	int u=root;
	while(true){
		int ls=tr[u].s[0];
		if(tr[ls].size+tr[u].cnt<k) k-=tr[ls].size+tr[u].cnt,u=tr[u].s[1];
		else if(tr[ls].size>=k) u=tr[u].s[0];
		else return tr[u].v;
	}
}

int num_for_rk(int v){
	find(v);
	return tr[tr[root].s[0]].size+1-1;
}

int main(){
	int m; cin>>m;
	insert(-INF), insert(INF);
	while(m--){
		int op, x; op=read(), x=read();
		if(op==1) insert(x);
		else if(op==2) remove(x);
		else if(op==3) cout<<num_for_rk(x)<<endl;
		else if(op==4) x++,cout<<rk_for_num(x)<<endl;
		else if(op==5) cout<<tr[pre(x)].v<<endl;
		else if(op==6) cout<<tr[suf(x)].v<<endl;
	}
	return 0;
}
Splay删除子树是一种数据结构和算法中的操作,通常用于自平衡二叉搜索树(如AVL、红黑树或Treap)的变种——Splay Tree中。Splay Tree是一种动态查找树,其特点是每次访问后都会对节点进行旋转操作(splaying),使其最近被访问的节点处于根部。 当要删除一个节点时,在常规的二叉搜索树中,我们需要找到该节点并删除它,然后处理可能由删除引起的不平衡。在Splay Tree中,这个过程有所不同: 1. **查找子树**: 首先,我们在树中寻找指定的子树,这可以通过标准的查找算法实现,同时保持对父节点的更新。 2. **Splay节点**: 找到子树后,我们对包含目标节点的路径上的所有节点执行一系列旋转操作(可能是单旋转或双旋转),直到目标节点到达根部。这个过程确保了频繁访问的路径被高效地访问。 3. **删除目标节点**: 当目标节点处于根部时,删除操作变得相对简单。如果目标节点有两颗子树,则替换为其右孩子的最小值或左孩子的最大值(取决于树的类型)。如果只有一个子树,那么就直接删除。 4. **重新平衡** (可选): 取决于Splay Tree的具体实现,可能会有一个额外的步骤来确保整棵树的平衡,但这不是必须的,因为Splay已经尽可能地减少了不平衡的可能性。 Splay删除子树的时间复杂度通常是O(log n),n是树的大小,因为每个旋转操作最多改变一棵高度为h的树的高度至h+1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值