Loading

学习笔记(4)Splay

·\(Splay\)(伸展树)

是一种通过将所有操作转换至根节点位置以改变树的结构,保证均摊时间复杂度(操作均为 \(O(log_{n})\) )的一种平衡树,主要通过上旋操作 \((rotate)\) 与双旋操作 \((splay)\) 维持树的结构与 \(bst\) 性质

更形象点说,该平衡树将“更频繁使用”的数据放在根节点及其临近位置,那么对于一些操作可以适当“偷懒”

比如:

·例题:

\(P3369\) 【模板】普通平衡树

住意由于 \(remove\) 操作会先调用一次 \(find\)__\(rank\) 操作及 \(pre\) 操作,因而将其写在最后面。同时写封装的话可以避免在需要多棵树的时候复制粘贴大段代码

纯模板题,code:

#include <bits/stdc++.h>
#define N 100005
using namespace std;
int n;
struct Splay{
	int root,tot;
	int val[N],cnt[N],par[N],siz[N],son[N][2];
	int add(int k){
		val[++tot]=k;
		par[tot]=son[tot][0]=son[tot][1]=0;
		siz[tot]=cnt[tot]=1;
		return tot;
	}
	int which(int now){return son[par[now]][1]==now;}
	void clean(int now){val[now]=cnt[now]=par[now]=son[now][0]=son[now][1]=siz[now]=0;}
	void pushup(int now){siz[now]=cnt[now]+siz[son[now][0]]+siz[son[now][1]];}
	void rotate(int now){
		int fa=par[now];
		int anc=par[fa];
		int a=which(now), b=which(fa);
		par[son[now][a^1]]=fa;
		son[fa][a]=son[now][a^1]; son[now][a^1]=fa;
		par[now]=anc; par[fa]=now;
		if(anc) son[anc][b]=now;
		pushup(fa);
		pushup(now);
	}
	void splay(int now){
		for(int fa;fa=par[now];rotate(now)){
			if(par[fa]) rotate(which(now)==which(fa)? fa:now); 
		}
		root=now;
	}
	void insert(int k){
		int now=root, fa=0;
		while(val[now]!=k && now){
			fa=now;
			now=son[now][val[now]<k];
		}
		if(now){
			++cnt[now];
			pushup(now);
            pushup(fa);
		}
		else{
			now=add(k);
			if(fa) son[fa][val[fa]<k]=now;
			par[now]=fa;
		}
		splay(now);
	}
	int find_num(int k){
		int now=root;
		while(1){
			if(son[now][0] && k<=siz[son[now][0]]) now=son[now][0];
			else if(k<=siz[son[now][0]]+cnt[now]){splay(now); return val[now];}
			else k-=siz[son[now][0]]+cnt[now], now=son[now][1];
		}
	}
	int find_rank(int k){
		int now=root, ans=0;
		while(1){
			if(!now) return 0;
			if(k<val[now]) now=son[now][0];
			else if(ans+=siz[son[now][0]], k==val[now]){splay(now); return ans+1;}
			else ans+=cnt[now], now=son[now][1];
		}
	}
	int pre(){
		int now=son[root][0];
		while(son[now][1]) now=son[now][1];
		splay(now);
		return now;
	}
	int suf(){
		int now=son[root][1];
		while(son[now][0]) now=son[now][0];
		splay(now);
		return now;
	}
	void remove(int k){
		int pos=find_rank(k);
		if(!pos) return;
		if(cnt[root]>1){
			--cnt[root]; pushup(root); return;	
		}
		if(!son[root][0] && !son[root][1]){
			clean(root); root=0; return;
		}
		if(!son[root][0] || !son[root][1]){
			int old=root;
			root=son[root][0]+son[root][1];
			clean(old); par[root]=0; return;
		}
		int old=root;
		pre();
		son[root][1]=son[old][1];
		par[son[old][1]]=root;
		clean(old); par[root]=0; pushup(root);
	}
}T;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int op,x;
		scanf("%d%d",&op,&x);
		switch(op){
			case 1: T.insert(x); break;
			case 2: T.remove(x); break;
			case 3: T.insert(x); printf("%d\n",T.find_rank(x)); T.remove(x); break;
			case 4: printf("%d\n",T.find_num(x)); break;
			case 5: T.insert(x); printf("%d\n",T.val[T.pre()]); T.remove(x); break;
			case 6: T.insert(x); printf("%d\n",T.val[T.suf()]); T.remove(x); break;
		}
	}
	return 0;
}
posted @ 2024-06-02 21:09  HRcohc  阅读(6)  评论(0编辑  收藏  举报