【集训整理】 旋转treap模板


Treap是一种弱平衡的二叉搜索树,它同时符合二叉搜索树和堆的性质:

二叉搜索树:右子节点值>父节点>左子节点

堆:子节点的优先值比父节点值小

我们让每个节点的值符合二叉搜索树的性质,同时给每个节点赋一个随机的优先值,让优先值满足堆的性质。

由于优先值是随机的,一旦不满足堆性质就会产生旋转,所以就很难出现退化成链的情况,达到平衡的效果。

Treap分为旋转Treap和无旋treap两种,旋转treap的旋转操作分为右旋和左旋:

![image-20220703180723552](【集训整理】 旋转treap模板.assets/image-20220703180723552.png)

写成代码如下:

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值。

最后更新于