splay tree 伸展树
splay
- 性质: 二叉查找树: 左子树小于根节点,右子树大于根节点
- 均摊O(log n)时间复杂度
- 伸展树: 每次访问节点后,将该节点旋转到根节点位置
m次splay 大小n的代价为 (n+m) log n
https://www.cs.usfca.edu/~galles/visualization/SplayTree.html
操作
rotate(x):
- x 变为自己父节点, 保持二叉搜索树性质
- 根据x与父节点关系,有左旋和右旋, 注意到对称性,只研究一边 右旋
- 相关: 这个和红黑/avl 里的旋转一样, 只是红黑维护颜色性质,而avl维护深度性质,
- zig(右旋),zag(左旋)
1 | a c |
注意下面的x,这些表示节点id不表示值, 需要值的话 增加val[x]去记录, 因为树的形状保证了值的大小关系,所以只有插入/查找的时候需要具体的值,而旋转的时候不会改变值,只是改变树结构,所以不需要具体的val
1 | // 注意到上面b,e其实都没有动的,只有a,c,d之间的关系以及a的父节点在动 |
splay(x,root):
将x旋转到root所在的位置(代替root所在位置), 其中root原来需要是x的祖先节点
x到root距离
- 距离=0,直接结束
- 距离=1, rotate(x) 即可
- 距离>=2
- 且 x是fa[x]左儿子,fa[x]是fa[fa[x]]左儿子( 同为左儿子,或同为右儿子), 先旋转父节点,再旋转子节点: rotate(fa[x]), rotate(x)
- 有拐点(是父的左,父是父父的右,或者是父的右,父是父父的左), 旋转x两次: rotate(x), rotate(x)
1 | void splay(int x,int target){ |
显然 上面操作保持了二叉的性质,但没有直接证明 log n的性质
查询/增加
正常的二叉树搜索,但是如果搜索到,同时splay(x,root)
1 | int find(int v){ |
1 | void insert(int v) { // 也可以自定义 类型 |
合并 树u,树v, 其中u全部小于树v
join(u,v)
- u 最大的节点一直走右节点x
- splay(u,rootu)
- r[x] = rootv
- fa[rootv] = x
split(x) 和删除类似
- splay(x,root)
- 左右就是切割出来的
删除x
- splay(x,root)
- join(l[x],r[x])
扩展: 查询个数
- 增加size字段, 在上面旋转中维护
区间:
- 双开区间
(i....j)
- splay(i,root)
- splay(j,r[i])
- l[j] 就是区间
lazy tag
- 类似segment tree 表示对子树的批量操作
复杂度分析
势能分析法
- 单个节点势能 = w(u) = log(size(u)), 子树大小的log
- $\varphi(tree) = \sum w(u)$, 整个树势能 = 所有节点势能和
- 操作代价 $c_i= t_i + \varphi_i - \varphi_{i-1}$ 单次代价 + 势能变化
性质:
- 父节点势能更大 w(fa[u]) > w(u)
- 根节点势能不变 w(root) = w(new root)
- size(p)>= size(x)+size(y) 则 2w(p)-w(x)-w(y) >= log 4
- 证明: 右侧 $= \log(\frac{size(p)^2}{(size(x)size(y))})$
- $\ge \log(\frac{(size(x)+size(y))^2}{(size(x)size(y))})$
- $\ge \log 4$
- 对于log 我们取 $\log_2$, 则得到 2
分析: 操作前f是父节点,x是子节点,g是fa[f]
- zig 操作
- w是操作前,w’是操作后
- 受到影响只有x,f
- w(f) = w’(x) 操作前f势能 = 操作后x势能
- $w’(x) \ge w’(f)$
- $c_i = 1 + w’(f) + w’(x) - w(f) - w(x)$, $t_i$记作1
- $c_i = 1 + w’(f) - w(x)$
- $\le 1 + w’(x) - w(x)$
- zig-zig
- $c_i = 2 + \sum w’ - \sum w$
- $= 2 + w’(f) +w’(g) - w(x) - w(f)$
- $\le (2w’(x)-w(x)-w’(g)) + w’(f) +w’(g) - w(x) - w(f)$
- $= 2(w’(x)-w(x)) + w’(f) - w(f)$
- $\le 3(w’(x)-w(x))$
- zig-zag
- $c_i \le 2(w’(x)-w(x))$ 类似的
- splay
- zig至多一次,若干次 zig-zig/zig-zag 一类的
- 总的代价在 $3(w^{t}(x)-w(x))+1\le 3\log n + 1$
我没有懂这个势能证明 与 代价之间如何建立最终的证明的
这个能证明,在当前的势能评价体系下,每次操作的 势能评价都是log级别的,但是 没有看到 总操作代价 与 势能函数 之间建立的 数值关系?
- 搜了几篇 都是 感觉上 让结构更好势能更小了,我也有这个“感觉”,但没有什么严谨的玩意?
下面的题目会发现,如果用到了一些翻转, 那么这个“值”其实难以维护的,但是能维护相对关系
相关资料
Tyvj1728 luogu3369, https://www.luogu.com.cn/problem/P3369
Tyvj1728 luogu6136, https://www.luogu.com.cn/problem/P6136
1 |
|
luogu p3391【模板】文艺平衡树 https://www.luogu.com.cn/problem/P3391
1 |
|