首页 > 技术文章 > 数据结构区间问题总结

aininot260 2018-07-27 16:15 原文

本文章作为这一段时间学习的阶段性总结

虽然我本来打算把这每一个点都深究完了之后再去写总结的,但是这样很容易让自己比较迷茫,所以这就是一篇阶段性总结了

这里所说的区间问题,是和树比较独立的一个概念,针对树的一些操作,有LCT,树链剖分,点分治,LCA这些知识,可能以后会有树问题的总结吧o(* ̄︶ ̄*)o

这篇总结所总结的东西都具有一个特点,就是可以强制在线,如果题目要求了强制在线,就必须用这些复杂数据结构了

然而,我们如果不要求强制在线,可以用CDQ分治\整体二分以同样的时间复杂度来完成这些操作

而对于一些不容易用这些复杂数据结构实现的,比较难的题目,在时间卡的不是特别死的情况下,分块儿和莫队算法是优秀的

我们一下提及的所有的方法,都是针对某一个区间或者某一个点,进行写改删查

我们一层一层来加大难度

首先,就是静态区间问题,啥是静态区间问题?就是区间不允许进行修改,更不允许进行插入删除的操作

在这种情况下,我们可以做些什么呢?

如果我们想查询静态区间的区间最值,可以使用ST算法:https://www.cnblogs.com/aininot260/p/9373443.html

如果我们想查询静态区间的区间和,请直接做前缀和

如果我们想查询静态区间的区间众数,那么就是分块儿大法了,或者说复杂的线段树也可以维护,这个问题限于目前的水平,以后再讨论

然后就是带修区间问题,带修区间问题指的是不允许插入和删除元素或者序列,但是可以进行区间的修改,典型的区间修改就是这个区间的所有数加上一个数

如果我们想修改点,查询区间和,请直接用一维树状数组:http://www.cnblogs.com/aininot260/p/9304826.html

如果我们想修改区间,查询点,请使用差分数组或者是差分树状数组:http://www.cnblogs.com/aininot260/p/9333351.html

如果我们想修改区间,查询区间和,请直接使用加强版树状数组(这个无敌,吊打线段树):http://www.cnblogs.com/aininot260/p/9333351.html

如果我们想修改区间(包括区间翻转、区间重置),查询区间和,查询区间最值,请使用带lazy tag的线段树:http://www.cnblogs.com/aininot260/p/9304936.html

以上的东西,都是几年前参加NOIP时候的老底,也是作为一个OI选手的数据结构老底

说到这里,我们打断一下,介绍一下什么是典型平衡树操作:

插入x数 
删除x数(若有多个相同的数,因只删除一个) 
查询x数的排名(若有多个相同的数,因输出最小的排名) 
查询排名为x的数 
求x的前驱(前驱定义为小于x,且最大的数) 
求x的后继(后继定义为大于x,且最小的数)

然后我们引入动态区间问题,所谓动态区间,就是支持在区间内插入和删除一个数

对于典型平衡树操作,请直接使用Treap:http://www.cnblogs.com/aininot260/p/9330967.html

除了典型平衡树之外,对于区间更加剧烈的动态操作,请使用区间之王(Splay)来完成

区间插入
区间删除
区间重置
区间翻转
求区间和
求整个区间和最大的子序列,并输出最大和
区间的分裂
区间的合并

请注意Splay不仅仅具有以上操作,典型平衡树操作也可以完全实现(BST通性)

如果想处理典型的动态区间问题,请直接使用,Splay:http://www.cnblogs.com/aininot260/p/9326793.html

这两种树介绍完了之后,后面的东西,就有意思了

我们讨论一个问题,那就是在限定区间内求第K极值,如果不限制区间的范围,任何一种BST都可以搞定,但是如果限定了范围,就要有一些,有意思的做法了

针对这个问题,我们还是从简单到难逐层来介绍,首先是静态区间的第K极值的查询,请直接使用主席树:https://www.cnblogs.com/aininot260/p/9370517.html

然后,就是带修区间的第K极值查询,让原本静态的主席树可以支持修改,那么就是树状数组套主席树了,这里貌似是离线的,等以后再深究:https://www.cnblogs.com/aininot260/p/9372788.html

然后就是进行区间范围内的拓展,不只是第K极值查询了,而是支持限定区间内的平衡树操作,当然,这里是带修区间的平衡树操作,直接线段树套平衡树来做:https://www.cnblogs.com/aininot260/p/9368669.html

下面列举一下操作都有哪些:

查询k在区间内的排名
查询区间内排名为k的值
修改某一位值上的数值
查询k在区间内的前驱(前驱定义为小于x,且最大的数)
查询k在区间内的后继(后继定义为大于x,且最小的数)

线段树套平衡树可以把前面的问题都解决地明明白白的,只不过代码稍长,时间复杂度捉急。然而,还是很好理解的。

最后呢,就是针对动态区间的第K极值查询,由于外层的区间是动态的了,那么外层就需要一棵平衡树来维持了,由于还要维护区间内的极值,采用权值线段树来做

这种套法还是比较讲究的,详细见替罪羊树套权值线段树:https://www.cnblogs.com/aininot260/p/9367918.html

到目前为止,在我学习的知识范围内的,能够解决地问题,大概就是这些了,接下来的一些高端操作,整体二分/CDQ分治,以及分块儿与莫队算法

我打算在过完“一轮预习”之后,回过头来再学,据说一层一层学习效果更加理想

推荐阅读