【学习笔记】【算法】【施工ing】Splay
好吧,Splay 还是要学的。
定义
Splay 是一种平衡 BST(二叉搜索树),通过伸展操作不断将某个节点旋转到根节点,使得整棵树既能满足 BST 的性质,又可以保证树不会退化为链。
而 Splay 的核心,就是在如何实现把点搬到根的这一操作。
Splay 的复杂度是 ,证明不重要所以。
基本操作
-
pushup(x) 不用解释吧,就是更新 。
-
get(x) 判断 是其父亲的哪个儿子。
- clear(x) 销毁 。
void pushup(int x) { siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x]; }
bool get(int x) { return x == ch[fa[x]][1]; }
void clear(int x) { ch[x][0] = ch[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0; }
rotate 操作
为了使 Splay 保持平衡而进行旋转操作,旋转的本质是将某个节点上移一个位置。
旋转需要保证:
- 整棵 Splay 的中序遍历不变,即不能破坏二叉查找树的性质。
- 受影响的节点维护的信息依然正确有效。
- root 必须指向旋转后的根节点。
旋转分两种,左旋与右旋,也叫 zig 和 zag。
具体分析,以 zig 为例,设需要旋转的节点为 ,其父亲为 :
-
将 的左儿子改为 的右儿子,且若 有右儿子,将其的父亲改为 。
-
将 的右儿子改为 ,也把 的父亲改为 。
-
若原来的 还有父亲 ,那把 的儿子替换为 。
void rotate(int x) {
int y = fa[x], z = fa[y], chk = get(x);
ch[y][chk] = ch[x][chk ^ 1];
if (ch[x][chk ^ 1]) fa[ch[x][chk ^ 1]] = y;
ch[x][chk ^ 1] = y;
fa[y] = x;
fa[x] = z;
if (z) ch[z][y == ch[z][1]] = x;
pushup(y);
pushup(x);
}
Splay 操作
将一个节点 旋转到根节点。
Splay 操作分为三种,具体六个情况,设当前点为 ,其父亲为 ,父亲的父亲是 :
- zig/zag 在 为根节点时,用 zig/zag 来将 旋到根上,只有刚好在 Splay 操作的点是奇数深度时在最后一步做一次。
- zig-zig/zag-zag 在 并非根节点且 和 同边时操作。两次都对 操作,如下图:
- zig-zag/zag/zig 在 并非根节点且 和 并不同边时操作。如下图: