[洛谷P3369] 【模板】普通平衡树——从BST开始说起(施工中

[洛谷P3369] 【模板】普通平衡树

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入 (x)
删除 (x) 数(若有多个相同的数,因只删除一个)
查询 (x) 数的排名(排名定义为比当前数小的数的个数(+1))
查询排名为 (x) 的数
(x) 的前驱(前驱定义为小于(x),且最大的数)
(x) 的后继(后继定义为大于(x),且最小的数)

Input

第一行为(n),表示操作的个数,下面(n)行每行有两个数(opt)(x)(opt)表示操作的序号((1≤opt≤6))

Output

对于操作 (3,4,5,6), 每行输出一个数,表示对应答案

Example

输入 #1

(10)
(1) (106465)
(4) (1)
(1) (317721)
(1) (460929)
(1) (644985)
(1) (84185)
(1) (89851)
(6) (81968)
(1) (492737)
(5) (493598)

输出 #1

(106465)
(84185)
(492737)

Scoring

对于 (100%)的数据,(1≤n≤10^5)(|x|≤10^7)

首先引入一种数据结构叫二叉排序树(又叫二叉查找树),即BST
它有下面的性质
(1)若左子树不空,则左子树上所有结点的值均不大于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均不小于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
简单说,就是一个结点的左边都比它小,右边都比它大
例子:

显然,这棵树的中序遍历的输出结果就是这些结点从小到大的排序结果
插入:

BST可以支持以下操作:
1.插入:小了往左走,大了往右走,走到底就新建点
2.删除:叶子结点直接删除,否则就把右子树的最小节点换上来,再删除右子树的最小节点
3.查询排名:所有的左边的点的个数 + 1(具体看代码)
4.查询数值:左子树大小比要求的排名大就往左走,不然往右走
5.求前驱:首先找到这个数,然后走到左儿子,再一直往右走到头就是了
6.求后继:同上,走到右儿子然后一直往左走

好了这题做完了,为什么需要Treap呢

当插入的数是递增或者递减的时候,它就会变成这样:

直接被卡成O(n)了

这时候我们就要通过一种操作——旋转来维持它的平衡,也就是让它的左右子树不要相差太大

当当当——平衡树!

操作有两类,分别是左旋右旋
左旋,就是把原来的右儿子放到自己的位置,自己成为它的左儿子,见图:

右旋同理,就是左旋的镜像:

旋转可以让平衡树变得更扁平。研究表明,在随机条件下,BST可以非常优秀,所以我们给每一个新插入的点一个随机优先级,然后根据它来旋转

看代码:

原文地址:https://www.cnblogs.com/Sheffield/p/13713182.html