这类求数列上区间第K大数的题目非常非常多(当然题目要求通常是求区间第K小)。
比如HDOJ 2665,POJ 2104,SOJ 3147,SOJ 3010,SOJ 3102(只计算一次),POJ 2761(区间不包含)。
求解这个问题的方法也非常多,在这里对几种我认为比较常见的方法做一下总结,今后也会不断补充。
当然,几乎所有的高级数据结构都可以用来求区间第K大数,我也认为这是初学一个数据结构时的一个很好的练习。
高级数据结构是我的软肋之一,如果代码写的有什么不优越的地方,欢迎神犇指教 > < 。
1、快速划分
最简单的方法,当然就是用类似快排的方法做快速划分,
每次随机选取一个数作为“主元”,以“主元”为分界线把当前区间的数划分成两部分,并找出“主元”的精确位置,然后不断递归。
关于这个算法的讲解可以看MIT的《算法导论》公开课。
无奈我太蒟蒻,怎么都是TLE,大家姑且一看:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
2、二叉堆
用一个容量为K的二叉堆,把当前区间的元素全部入堆,但是每次只保留这个堆中前K小的数,最后这个堆中的堆顶元素即为所求
这个算法肯定更加是TLE的,我相信即使手写堆也多半时过不了的,给大家写一段代码示意一下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
3、树状数组
小伙伴们喜闻乐见的树状数组也可以用来求区间第K大数哦!
树状数组中的+-lowbit,实际上就是在“树”上实现了跳到父节点/子节点的操作。
由此可以二分地求出第K大数。
参考了clj的代码和一篇解题报告,这个是只能在固定区间求的。
当然想要在任意子区间求显然也不难,只要每次重新建树就可以了。
和上面一样,这个代码也是无论如何都过不了的 > < 。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-------------------------------------------------------------------------下面介绍几种不TLE的----------------------------------------------------------------------------
4、划分树
划分树是一种线段树。
可以用来求区间第K大。
学划分树墙裂建议做一下HDOJ 4417,可以通过对代码稍加改动,由求区间第K大转化为求区间内小于某个值的数有多少个(不需二分哟)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
5、归并树
归并树跟划分树是一对好基友。
不过我短时间内不打算学。
先开个坑,丢个别人的解题报告:
6、主席树(可持久化线段树/函数式线段树)
主席树的核心要义,就是每次更新都只新建被更新了的节点(O(lgn)个),而保存历史版本
感谢sd6001和ftiasch的模板
数组版:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
动态分配内存版:
注意:由于这个模板只有new没有delete,所以可想而知所有case的申请内存都叠加在了一起,分分钟MLE无鸭梨。
目前这个模板只能过SOJ 3147。不过在单case评测的OJ,这样写还是很优雅的。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
7、Treap
Treap做区间第K大数最好做POJ 2761,因为这道题有个条件是区间不包含,否则复杂度会上升很多。
这道题实际上就是维护一个FIFO队列,使得处理某个询问时,treap中只包含正在询问的这个区间。
感谢 ftiasch 的模板。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
8、红黑树
这个必须可以搞。。
不过正常人不会想要手写红黑树吧。。
所以也无限期搁置。。
9、SPLAY
待学。
稍安勿躁 >_<