关于求解区间第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

而且整体二分似乎可以处理带修改的情况。

posted @ 2018-10-03 15:14  praying_cqf  阅读(356)  评论(0编辑  收藏  举报