作为平衡BST里最简单的版本,Treap光是模板的难度就已经超过了提高+,达到了 省选 (luogu上的紫色标签)。但是NOIP去年还真的考了一题!因此有必要认真的学习一下。(这也是大学CS数据结构课的标配,早晚要学,不如现在学掉)。
本蒟蒻敲这个模板花了一个小时,调bug又花了半个小时。感谢lyd的算法竞赛进阶指南,他的代码是我唯一看得懂的一个treap版本。网上那些用指针实现的,阅读并不容易而且溢出调试麻烦….
原理不说了,出门右拐百度百科。https://baike.baidu.com/item/Treap/4321536
这里只列举一下写treap时易错的点。并且根据我的洛谷WA记录,treap一错那多半是大量RE, 很容易爆零 ,所以下面的坑一定要避而远之哦!
Treap易错点
- 初始化时添加最小点和最大点,他们之间的关系容易写错。
- 插入操作时最后需要维护当前节点的附加信息,如子树个数等,容易遗忘。
- root节点在初始化时需要额外手动指定,容易遗漏。
- 函数名如new、insert、update等注意不要踩C++编译器关键字。
- 查前驱后继时,找到并更新答案(左走到底和右走到底)应应时刻判断当前节点p为空的情况:进入while之前设置if判断是否存在左/右节点以便进入while;在while中判断tn[p].l/r是否存在,而不是判断p是否存在。后者会造成越界访问不存在的虚拟节点0,造成答案错误。
- 任何对treap的修改(插入、修改、删除、旋转)都要执行update命令,并且注意update顺序:先update儿子节点,再update当前节点。
- 对treap的修改、递归执行时,定义函数时把当前节点的传参设为引用。否则会导致更新失败。
- 删除操作时判断左旋还是右旋,左旋条件为右子树为空,或者左子节点treap key堆键值比右子节点大。两条件顺序不可颠倒,关系为或。 并且不要写成判断左子树是否存在,那是错的,会导致虚拟节点旋转上树进而造成树的断裂。
- 按排名查找值和按值查找排名时,注意treap初始化时无穷大和无穷小节点的影响。为去除这两个节点的影响,输入排名时应+1,按值找到排名时应-1.
以下给出一份AC代码,对应
luogu上的treap模板题
https://www.luogu.org/problemnew/show/P3369
bzoj上的模板题
http://www.lydsy.com/JudgeOnline/problem.php?id=3224
请展开阅读
完整代码
1 |
|