WBLT_随笔
WBLT
足够优秀,但其缺憾有几点:
- 并不 ,合并需要合并三份而不是两份,在上面进行线段树操作更加繁琐,查询区间信息需要裂开合并,不能直接像线段树一样求。
- 如果对其进行可持久化,倘若新节点的随机权值直接复制原节点,那么我们无法进行“拼接两棵已有的平衡树”,一个节点自己拼接自己 次就足以让随机权值爆炸。
- 每次随机难以调试,不过这并不是大问题,调试时使用固定的随机种子即可。
解决第二个问题,目前主流的做法是抛弃随机权值,而是合并时按照 加权随机谁当根,这个做法目前处于无人会证且无人会卡的尴尬境地,所以可以放心使用。
另一个选择是学习 ,它的 和自动支持可持久化是很有用的。
Leafy 化
将一棵树 化,最大的不同就是原本一棵 个节点的树现在需要 个节点来表示,所以节点的使用权不应在使用者手上,应该在数据结构的手中。
由于平衡树需要频繁地拆解、新建, 通常需要垃圾回收以减小空间常数。
这就很自然地引出了 new_node,uni,del 三个函数。
1 | int new_node() { |
WBLT 的平衡策略 & 分裂合并实现
有一个平衡常数 ,每个非叶子节点都要保证 ,对于常见的写法, 大约在 之间时,可以保证理论复杂度,通常取 常数小,此时可以用位运算优化乘法。
非旋平衡树因为理念简单广受好评,此处我们也采用非旋写法。
唯一重要的是其 ,即左右拼接两棵树的过程,其余部分都并不涉及平衡策略的应用。
根据集训队论文的合并方式:在合并两棵树 时,若直接拼接满足平衡策略,则直接拼接。
否则我们找到更小的那棵,假设是 :
- 若 与 满足平衡策略,则递归
uni(mer(x,l(y)),r(y))。 - 否则, 都很小, 很大,我们递归
mer(mer(x,l(l(y))),mer(r(l(y)),r(y)))。
不会证复杂度。
分裂是简单的,我们仿照非旋 ,把裂开的几棵树向答案调用合并即可。
1 | int mer(int x,int y) { |
有了分裂合并,就自然地会插入删除二分等等操作了。
参考资料
IOI2018 集训队论文:Leafy Tree 及其实现的加权平衡树。
评论
评论插件加载失败
正在加载评论插件