整體二分可以算作是普通二分的進化版。普通二分可以解決多個操作,單個詢問。時間復雜度為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與很好的總結。