[洛谷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可以非常优秀,所以我们给每一个新插入的点一个随机优先级,然后根据它来旋转

看代码:

posted @ 2020-09-22 20:51  七离符  阅读(137)  评论(0编辑  收藏  举报