简介
splay树是一种二叉平衡树,支持splay操作;splay操作可以利用旋转使某个节点移动到某个祖父的位置,同时保持平衡树的性质。
旋转图解
1.左旋和右旋。该图为右旋(ZIG),反过来就是左旋(ZAG)。
2.双旋。当x要移动到z时,要进行两次旋转若对x直接旋转两次后,低效的链式结构还是存在,我们需要尽量消除链。
所以先对y旋转,再对x旋转,可以看到树的深度由3变为了2。
代码实现
1.节点结构
#include<bits/stdc++.h>
#define Ls(x) T[x].ch[0]
#define Rs(x) T[x].ch[1]
#define Fa(x) T[x].fa
#define root T[0].ch[0]
const int max = 10010;
int tot = 0;
struct node
{
int fa;
int ch[2];
int size;//子节点的数量,包含本身。
int cnt;//值出现的次数
int val;//值
}T[max];
2.index
用于判断x是其父亲的左儿子还是右儿子
int index(int x)
{
return T[Fa(x)].ch[0] == x ? 0 : 1;
}
3.rotate (旋转)
x成为祖父的哪个儿子与父亲是祖父的哪个儿子是一样的。
x的要改变爸爸的儿子是与index(x)^1,成为另一个爸爸的index(x)儿子。
x的爸爸变成了x的index(x)^1儿子
void connect(int x,int F,int way)
{
T[x].fa = F;
T[F].ch[way] = x;
}
void rotate(int x)
{
int F=Fa(x), GrandF = T[Fa(x)].fa;
connect(x, GrandF, index(Fa(x)));
connect(T[x].ch[index(x) ^ 1], F, index(x));
connect(F, x, index(x) ^ 1);
}
4.splay
void splay(int x,int to)
{
while (x != to)
{
if (Fa(x) == to)
rotate(x);
else if (index(x) == index(Fa(x)))
rotate(Fa(x)), rotate(x);
else
rotate(x), rotate(x);
}
}