(这里是Splay基础操作,reserve什么的会在下一篇里面讲)

好久之前就说要学Splay了,结果苟到现在才学习。

可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构。

感觉Splay比Treap良心多了——代码真的好写。

对于Splay显然可以维护Treap的所有操作,并且本质是BST。

先看看Splay是怎么维护普通平衡树操作的吧。

首先先定义一些基础的变量(若不作特殊说明这些变量的意义不变)

int t[N][2] // t[x][0]表示节点x的左子树,t[x][1]表示节点x的右子树

int cnt[N] // cnt[x]表示节点x存储多少个重复的数

int val[N] // val[x]表示节点x存储数的大小

int par[N] // par[x]表示节点x的直接父亲,特别的,根节点的直接父亲为0

int size[N] // size[x]表示在BST中x子树中存储数的个数

# define ls(x) (t[x][0])

# define rs(x) (t[x][1]) //方便书写

初始化:Splay平衡树中有有+无穷 -无穷两个哨兵节点!!!

Check(x) 函数 :

询问节点x是其父亲的左儿子(return 0)还是右孩子(return 1)

int check (int x)  { 
    return rs(par[x])==x;
}

由上述代码可知,根节点的check(root)值为0,即根节点是0节点的左儿子(Nothing Special)

Up(x)函数:

对于节点x维护其size值为两个孩子的size值+自身cnt值。

void up(int x){
    size[x]=size[ls(x)]+size[rs(x)]+cnt[x];
}

Rotate(x)函数:

对于节点x旋转到其父亲节点,且不改变树BST性质。(使得树形态较为随机)

这里需要解释一下Rotate的解释和记忆方法(和Treap中Rotate类似)

对于一棵有根树(且父亲指向儿子的边有向),我们现在以把左儿子旋到父节点为例。

文艺平衡树 Splay 学习笔记(1)

第1步,考虑4的右子树已经有元素了,考虑把右子树连接到父节点左儿子处。不改变BST性质。

文艺平衡树 Splay 学习笔记(1)

在此基础上考虑第二步,就是吧2(4的直接父亲接到4的右边)不改变BST性质。

文艺平衡树 Splay 学习笔记(1)

这个时候我们会发现,只进行第三部就可以完成一次rotate操作。

即连一条1指向4的边即可。

文艺平衡树 Splay 学习笔记(1)

对于左边节点转到父亲节点,一般称之为右旋

文艺平衡树 Splay 学习笔记(1)

对于右旋函数的代码,不难得到。

void rotate(int x){
  int y=par[x];
  t[y][0]=t[x][1]; par[t[x][1]]=y;
  t[x][1]=y; t[par[y]][check(y)]=x;
  par[x]=par[y]; par[y]=x;
  up(y); up(x);
}
右旋

相关文章:

  • 2021-06-19
  • 2021-08-05
  • 2021-08-26
  • 2022-01-14
  • 2021-05-20
  • 2022-01-22
  • 2021-08-24
  • 2021-10-25
猜你喜欢
  • 2022-12-23
  • 2021-05-31
  • 2022-02-10
  • 2021-11-10
  • 2021-12-25
  • 2021-11-01
  • 2021-10-28
相关资源
相似解决方案