Splay

IAKPSC就是个乐子,学的时候不写学习笔记,现在全忘了,不像人类

Splay 是一种平衡树,通过旋转维护平衡可以做到树高均摊 log

"Splay" ,查一下词典,是伸展的意思

顾名思义," 伸展 " 操作是维护一颗 Splay 的关键,而伸展的核心,便是旋转

盗一张图

旋转就是在满足二叉搜索树性质的同时改变树的形态

那上图是如何旋转的呢

再盗用先人一句口诀:左旋拎右左挂右,右旋拎左右挂左

这是hyw呢?我以右旋为例,略微解释一下

拎出 1 的左儿子 2,将 1 的父亲变为 2 ,2 的父亲变为原先 1 的父亲 ,2 原来的右儿子变为 1 的左儿子

旋转的 code

const int N=2e5+5;
struct node{
	int s[2];
	int siz,fa,key;
	node(){
		s[0]=s[1]=siz=fa=key=0;
	}
}tree[N];
#define fa(k) tree[k].fa
#define ls(k) tree[k].s[0]
#define rs(k) tree[k].s[1]
void maintain(int k){tree[k].siz=tree[ls(k)].siz+tree[rs(k)].siz+1;}
bool get(int k){return k==rs(fa(k));}
void rotate(int k)
{
	int x=fa(k),y=fa(x);bool c=get(k);
	if(tree[k].s[c^1]) fa(tree[k].s[c^1])=x;
	tree[x].s[c]=tree[k].s[c^1];
	tree[k].s[c^1]=x;
	fa(x)=k;fa(k)=y;
	if(y) tree[y].s[x==tree[y].s[1]]=k;
	maintain(x);maintain(k);
}

然后就是伸展了,伸展操作本质就是把一个点旋转至另一个点的下方

void splay(int x,int y)
{
	for(int f=fa(x);f=fa(x),f!=y;rotate(x))
	{
		if(fa(f)!=y) rotate(get(x)==get(f)?f:x);
	}
	if(!y) root=x;
}

这是压行写法,描述了一个双旋的过程,若 x 的爷爷不是目标点,旋转 x 的父亲 f ,再旋转 x ,通过双旋改变树的形态,至于这个三目运算符,貌似指的是如果 fa 在 x 同侧就旋转 x ,感性理解一下,可以提升效率

至于剩下的,就是依据平衡树特性以及 splay 操作的 “瞎搞搞” 了,读者发明不难

posted @ 2026-11-13 11:29  IAKPSC  阅读(3)  评论(0)    收藏  举报