关于求解区间第k大的在线和离线做法
Posted lmlysklt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于求解区间第k大的在线和离线做法相关的知识,希望对你有一定的参考价值。
最近做了一道关于整体二分的题。
很开心地涉足了关于求区间第k大问题。
问题:给定序列,若干询问,求区间第k小。
第k大类推。
离线算法:
整体二分。
将所有询问离线下来,挂在区间右端点先。
对所有询问二分答案mid。
那么序列上的数就可以划分为两类了,一类小于等于mid,一类大于mid。
用树状数组维护一下。
接着处理询问,对于每个当前的询问判断是否合法,然后将询问划分为两边,一边答案小于等于mid的,一边是大于mid的。
看一下复杂度,每次答案的范围除以2,每次二分分别扫描一次序列和询问,总复杂度O(nlog(n)log(maxans)+qlog(n)log(maxans))
离散化可以变成O((n+q)log^2(n))
在线算法:
划分树。
每个节点存储一个序列,存储的元素就是原序列排序后对应区间的元素,只不过顺序与原序列一致。
设父亲节点为(l,r)。
左节点存储的是小于等于在父亲节点中排名为mid的数的mid-l+1个数。
右节点存储在父亲节点中而不在左节点中的剩下的数。
儿子节点中数的排布顺序与在父亲节点中数的相对顺序一致。
顺便记录一下每个非叶子节点的前i个数有多少个存进了左儿子,记为num[i]。
查询的时候,例如我们要查询的区间为(x,y),当前节点对应的区间为(l,r),x>=l且y<=r
我们先看该节点的num[y]-num[x-1],如果小于k,那么说明我们要查询的第k小在右儿子中,改变一下查询的k,变为k-(num[y]-num[x-1]),进入右儿子;
否则就在左儿子啦,进入左儿子就好了。
看一下复杂度,建划分树的复杂度可以是O(nlog^2(n)),然而我们可以先弄出一个原序列的排序序列,就不需要每一层用排序去确定排名为mid的数了,变成了O(nlog(n)),每次询问也是一个log,所以总复杂度为O((n+q)log^(n))
这么说好像划分树完爆整体二分啊...人家还是在线的。
当然整体二分的空间是n级别的,划分树则需要nlogn
而且整体二分似乎可以处理带修改的情况。
以上是关于关于求解区间第k大的在线和离线做法的主要内容,如果未能解决你的问题,请参考以下文章
(树状数组+离线查询)HDU 4417 - Super Mario