整体二分
整体二分可以算作是普通二分的进化版。普通二分可以解决多个操作,单个询问。时间复杂度为O(所有操作的复杂度f(n)*logC), C为需要二分的答案范围。
那么Q个询问呢?显然所有操作的复杂度是 > O(n)的,每个询问所有操作来一遍,那么就变成O(Q*所有操作的复杂度f(n)*logC), 复杂度就爆炸了。
显然很多操作做一次会对多个询问产生贡献。由此产生了整体二分的算法。有点类似CDQ分治。
整体二分是将答案二分,并将操作与询问分别归类在在(l, m)还是(m, r)两个队列,同时算出其中一个对另一个答案的贡献。
以上。
附链接:
以区间第k小为整体二分框架
f(队首, 队尾, 二分下界l, 二分上界r){
if(队列空) return;
if(l == r) 队列内的所有询问答案为l, return ;
int m = 上下界中值;
扫描队列,处理询问与修改值小于m的修改操作(树状数组)。则询问结果存的是(l, m)内数的个数;
还原树状数组。
扫描队列:
若是修改操作,根据修改答案的大小丢进队列1与队列2;
若是询问操作,if 询问答案+当前贡献 >= 所需答案k 丢入队列1;
else 更新询问答案,丢入队列2;
f(队列1, l, m);
f(队列2, m+1, r);
}
**还原树状数组的复杂度不能与序列长度线性相关,否则会退化。只能与当前队列长度相关。
没做什么题,就看了一些别人的代码,了解了整体二分的思想。
来看一道例题:
有n个国家和m个空间站,每个空间站都属于一个国家,一个国家可以有多个空间站,所有空间站按照顺序形成一个环,也就是说,m号空间站和1号空间站相邻。
现在,将会有k场流星雨降临,每一场流星雨都会给区间[li,ri]内的每个空间站带来ai单位的陨石,每个国家都有一个收集陨石的目标pi,即第i个国家需要收集pi单位的陨石。
询问:每个国家最早完成陨石收集目标是在第几场流星雨过后。
数据范围:1<=n,m,k<=300000
思路:二分答案第k场流星雨,模拟(l, m)的流星雨,线段树区间更新后,单点求值(差分即可,复杂度会退化,需要满足不能与序列长度线性相关)。
更多例题请戳2013xhr与很好的总结。
诸神对凡人心生艳羡,厌倦天堂。