【集训整理】 旋转treap模板
Treap是一种弱平衡的二叉搜索树,它同时符合二叉搜索树和堆的性质:
二叉搜索树:右子节点值>父节点>左子节点
堆:子节点的优先值比父节点值小
我们让每个节点的值符合二叉搜索树的性质,同时给每个节点赋一个随机的优先值,让优先值满足堆的性质。
由于优先值是随机的,一旦不满足堆性质就会产生旋转,所以就很难出现退化成链的情况,达到平衡的效果。
Treap分为旋转Treap和无旋treap两种,旋转treap的旋转操作分为右旋和左旋:

写成代码如下:
void left_rotate(int& id) { //左旋
int tmp = rchild[id];
rchild[id] = lchild[tmp];
lchild[tmp] = id;
id = tmp;
push_up(lchild[id]);
push_up(id);
}
void right_rotate(int& id) { //右旋
int tmp = lchild[id];
lchild[id] = rchild[tmp];
rchild[tmp] = id;
id = tmp;
push_up(rchild[id]);
push_up(id);
}旋转操作其实只涉及两个点,交换下孩子即可。
树的储存,使用数组模拟结构体:
val存值,prio存节点的优先值,siz记录某节点的子节点的数量,cnt记录某节点的值出现的次数,用于处理重复元素的情况。
创建节点:
用rand函数给prio赋随机值。
更新siz的push_up操作:
在旋转/插入后siz可能会变化,要push_up从下到上更新。
初始化:
初始化要先往里边塞一个正无限和一个负无限节点。
插入:
在二叉查找树上找位置插入,找到树缺位或已有节点修改。每次插完都要检测符不符合堆的性质,如果不符合就用旋转的方式进行平衡。
注意,每层插入递归结束后都要进行一次push_up重新计算size值。
最后更新于