Splay操作集合
来源:互联网 发布:广东网络干部学院登录 编辑:程序博客网 时间:2024/06/18 16:43
Perface
先前学了一发Splay,觉得并不是很难,这里做一个小总结.
鉴于理解splay的文章很多,但真正有关模板的好文章很少,本文不会进行深入讲解,仅仅是把其对应的一些操作总结一下.
线段树 VS Splay
我们都知道对于一般序列上的问题,要维护的,一般都可能想到线段树.
但实际上,线段树能做的东西只是Splay能做的东西中的一个子集.
Splay vs 线段树
从代码难易程度上,显然线段树占优.
从一般时间上,线段树能做的题,速度大多比Splay快,ZKW优势明显.
但从用途上,Splay能做的东西就要多很多
例如在某某位置插入一个数,删除一个数,旋转一堆数,再询问答案.
这是线段树所做不到的.
splay基础操作
第一个操作:
Rotate(x) - 定义为把
x 旋转到x 父亲位置,并保证Splay的中序.
- 定义为把
注意:
son(x) 的简洁用法,以及两个if 和更新父子关系的先后顺序.其中
son(x) 可以如下使用:
第二个操作(Maintain):
Splay(x,y) - 定义为把
x 通过Rotate 操作旋转到y 的儿子中.
- 定义为把
其中,这个操作还有如下简洁地写法:
第三个操作(区间修改操作):
remove(x,y) - 定义为把从
x−>y 这一条路径上所有的标记释放.
- 定义为把从
其中
clear 操作如下实现:这里的情况显然是给一段数加个值.
lazy 操作则可以根据所需情况实现:
第四个操作(求答案):
update(x) 定义为处理
x 点的答案..
注意到,仅用以上四个操作,我们就可以完成基本的
splay 操作,我们几乎可以切掉所有线段树能切的题了.但接下来,我们还是得讲一些比较nb的操作:
以:http://www.lydsy.com/JudgeOnline/problem.php?id=3224此题为例.
需要支持的操作有:
插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
求x的后继(后继定义为大于x,且最小的数)
Splay进阶操作
操作一:
insert(x) - 定义为在一颗
splay 中插入权值为x 的点.
- 定义为在一颗
我们看一下这个操作有什么需要注意的:
①我们需要判断
root 是否为0 ,如果是,代表当前树为空,进行特殊操作.②然后我们从
root 开始走,每次需要判断当前的x 是否以前出现过,出现过则加计数器③否则,我们就可以新开节点.
④这里需要注意的是update操作,有人可能会不解,这里没有进行
remove 操作,如何保证insert 后所有的节点都被更新?- 对于这一点,你只需要关注:
splay(now,0) 这一条语句即可.
- 对于这一点,你只需要关注:
操作二:
find(x) - 定义为找到权值为
x 点的排名(若有多个相同的,因输出最小的排名)
- 定义为找到权值为
这个操作需要注意的不多:
但也需要时刻关注题目,这里的rank+1很关键
以及代码是如何处理节点的去向,最后,最关键的是:
一定要记得
splay(now,0) ,否则均摊会失效.
操作三:
pre() - 定义为求
root 的前驱,当然我们也可以设为x 的前驱.
- 定义为求
操作四:
next() - 定义为求
root 的后继.
- 定义为求
操作五:
update(x) 这里的定义为维护子树大小.
我们也可以理解为我们需要维护的一些东西.
操作六:
delete(x) - 定义为把权值为
x 的点给删掉一个.
- 定义为把权值为
这是一个比较麻烦的操作:
第一,我们需要注意对于左子树空,右子树空,当前
x 有多个节点时的特殊处理.很重要的一步是,
find(x) ,目的很显然了,就是把权值为x 的点移到树根.注意,这里万万不可直接
splay(x) ,因为权值和编号是不一样的概念.splay的形态是按权值的,但具体记录父亲儿子是按编号的.
然后如果左儿子右儿子都存在时,我们可以
pre() 找到刚好比x 小的一个点作为根,然后再修改父子关系.最后注意一定要
clear(root) 以及update(root)
操作七:
fim(x) - 定义为寻找排名为
x 的权值.
- 定义为寻找排名为
这应该就很好理解了吧,注意rank+size[tr[nw][0]]中的rank一词.
拥有以上七个操作,这道题就可以迎刃而解,但是我们还有一些细节需要注意:
如果我们要求
x 的前驱,我们可以先插入这个节点,然后再找,最后记得删掉,求后继一样.这样很方便.
总结
从此文我们可以看到splay的强大之处,以及C++的简洁之处.
我们需要注意的是核心
splay(x,y) 不管对于什么样的操作,insert也好,delete也好,都一定要把我们进行操作修改的点
splay 一下.这是核心,一定时刻牢记.
一句话:splay是越多越好.
其次,我们还需要注意在
rotate 的时候一定要先update(y) 再update(x) ,原因很显然.- 然而如果不这么做交到Bzoj上还是能A掉…
- Splay操作集合
- splay操作集合
- Splay tree的splay操作
- 维护集合Ⅱ【Splay】
- splay区间操作
- 【Splay操作】续.....
- Splay操作总结
- 【POJ3468】区间操作 Splay
- Splay树简单操作
- Splay 的区间操作
- splay模板基本操作
- poj3580SuperMemo(splay丰富的操作)
- Splay Tree的删除操作
- splay各操作伪代码
- bzoj1251(splay序列操作)
- SPLAY
- splay
- splay
- STM32的心得
- A. Nephren gives a riddle dfs
- LWC 62:744. Find Smallest Letter Greater Than Target
- 递归与迭代
- 【从零学权限框架】——概念认知
- Splay操作集合
- proc far and near. 的简单解释
- angularJS中$http.get( ).success( )报错原因及解决方案
- 基础
- unity添加天空盒的两种方式
- LTE-怎么获取上行资源
- 线程
- <编译原理>短语、直接短语及句柄
- jquery插件冲突解决方法