幸甚至哉,歌以咏肝
TIPS:文字量不多,感性理解。
BST性质
对于任何BST上的节点,其左子树的节点权值小于当前节点,右子树的节点的权值大于当前节点,因此这个性质能够很好地维护单调性,直接中序遍历即可得到答案。
当然也可以方便查询大小排名,前驱后继等等
也可以来搞LCT,也可以满足一些出题人的奇怪癖好,比如仙人掌上差分 .
Splay
Splay可以防止平衡树退化,通过不断旋转来不断维持自身的平衡性,
旋转
旋转时我们向子节点在父节点的方向的反方向旋转.
这样就可以保持BST的性质,又能维护平衡
于是,异或就可以完美地解决这个旋转。
直接修改相应的父子节点和节点信息即可
找方向
1 | inline int get(int x) |
上传(维护size)
1 | void push_up(int x) |
旋转
1 | inline void rotate(int x) |
Splay
我们用Splay处理被更改的所有节点,使其再次满足平衡性质,这是为了保证查找复杂度。
1 | inline void splay(int x,int go=0) |
插入节点
注意第一个插入的节点要特判,之后需要不断向下寻找位置。
然后再进行Splay,维护平衡性
1 | inline void insert(int x) |
辅助函数
将小于等于x的树Splay到根
1 | void find(int x) |
查找第K大的数
因为满足了BST的性质,并且我们在建树的过程中记录了SIZE,那么我们就可以很容易地用SIZE和BST的性质来进行查找,这个过程可以看成不断“切树”的过程,直到x被切完
1 | int k_th(int x) |
前驱
这个就没什么好讲的了,直接查找即可。后驱同理
1 | int pre( int x) |
后驱
1 | int next(int x) |
删除
若存在这个点,就直接将计数器减一,若只有一个,暴力,改变前驱后继,并Splay维护BST性质
1 | void del(int x) |
完整代码
1 |
|