yang-xi-jie-mi-zheng-ti-er-fen

详细揭秘 整体二分

考虑这样一个问题:

  • 给你一个序列,每次查询区间 kth。

如果你不会主席树,你可能会考虑二分答案:二分一个 mid,看看它在区间中的 rank,与 k 比较。

这样子单次暴力是线性对数的,不太妙。问题出在哪里呢?你发现每次找 rank 是线性的,很慢。

我们把多个询问放在一起跑二分,即 整体二分,具体的:

  • 用类似二分答案的思想,确定一些询问的答案区间 [l,r]。假设我们现在正在解决答案在 [l,r] 内的询问。

  • 二分 mid=l+r2,将答案在 [l,mid][mid+1,r] 的两类询问分开。

如何分开这两类询问?类似地,我们比较 mid 在每个询问的区间中的 rank 和这个询问的 k 的大小。

现在这个 rank 要怎么找?你想要知道在序列上一个区间 [L,R] 内有多少数 <mid

注意这里只需要考虑原序列中值域在 [l,r] 中的数,那么把这些数中比 mid 小的数拉出来,

将它们在序列上的位置 +1,查询 [L,R] 的和就是你想要的。

询问分开了,那么我们递归下去直到 l=r,那么相当于二分答案结束了。注意分到右边的询问的 k 要减 rank。

这样每一层复杂度是 O(n) 的,总复杂度为线性对数。

例题:

[POI2011]Meteors

相当于二分答案时间,看该站在这个时间前是否完成任务。

每场陨石雨相当于区间修改,每次只执行 [l,mid] 的陨石雨(区间加),

检验每个站点的值是否已经满足条件即可,也就是单点查询。

[CF603E]Pastoral Oddities

原题条件等价于每个连通块大小为偶数,这里不证,不是本文重点。

随着时间推移,答案肯定越来越优,也就是答案具有单调性。维护连通块肯定是用并查集了。

考虑单次二分答案的算法。对于时间 i 的询问,我们二分一个权值 mid,然后加入所有时间 i,权值 mid 的边,看一下是否所有连通块都是偶数。

现在变成整体二分。分治存当前处理的时间区间 [tl,tr] 和对应答案区间 [wl,wr]

wmid=wl+wr2。考虑将时间区间拆成两部分,第一部分的答案在 [wmid+1,wr] 中,另一部分答案在 [wl,wmid] 中。

在进入这层分治前用并查集内维护好权值 <wl 且时间 <tl 的所有边。现在我们向并查集内加入权值 [wl,wmid],时间 <tl 的边。

这样并查集里就有权值 wmid,时间 <wl 的边。这和我们单次二分要求的范围很类似了,接下来继续扩展:

  • 依次加入时间 [tl,tr],权值 wmid 的边,直到满足所有连通块都是偶数。

满足条件就可以停下来了,现在我们找到了一个分界线 x,满足时间 [l,x] 的都没办法只用 wmid 的边满足条件,而时间 [x+1,r] 的都能用 wmid 的边满足条件。这就说明,时间 [l,x] 的答案都在 [wmid+1,wr] 中,时间 [l,x] 的答案在 [wl,wmid] 中。

分治下去即可。注意需要维持进入这层分治前用并查集内维护好权值 <wl 且时间 <tl 的所有边。

需要支持并查集的撤销,用可撤销的并查集即可。

复杂度会发现每一层加边的数量加起来都是线性,所以复杂度 Θ(nlog2n)

posted @   iorit  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示