詳細揭秘 整體二分
考慮這樣一個問題:
- 給你一個序列,每次查詢區間 kth。
如果你不會主席樹,你可能會考慮二分答案:二分一個 \(mid\),看看它在區間中的 rank,與 \(k\) 比較。
這樣子單次暴力是線性對數的,不太妙。問題出在哪裡呢?你發現每次找 rank 是線性的,很慢。
我們把多個詢問放在一起跑二分,即 整體二分,具體的:
-
用類似二分答案的思想,確定一些詢問的答案區間 \([l,r]\)。假設我們現在正在解決答案在 \([l,r]\) 內的詢問。
-
二分 \(mid=\frac{l+r}2\),將答案在 \([l,mid]\) 和 \([mid+1,r]\) 的兩類詢問分開。
如何分開這兩類詢問?類似地,我們比較 \(mid\) 在每個詢問的區間中的 rank 和這個詢問的 \(k\) 的大小。
現在這個 rank 要怎麼找?你想要知道在序列上一個區間 \([L,R]\) 內有多少數 \(<mid\)。
注意這裡只需要考慮原序列中值域在 \([l,r]\) 中的數,那麼把這些數中比 \(mid\) 小的數拉出來,
將它們在序列上的位置 \(+1\),查詢 \([L,R]\) 的和就是你想要的。
詢問分開了,那麼我們遞迴下去直到 \(l=r\),那麼相當於二分答案結束了。注意分到右邊的詢問的 \(k\) 要減 rank。
這樣每一層複雜度是 \(\mathcal O(n)\) 的,總複雜度為線性對數。
例題:
[POI2011]Meteors
相當於二分答案時間,看該站在這個時間前是否完成任務。
每場隕石雨相當於區間修改,每次只執行 \([l,mid]\) 的隕石雨(區間加),
檢驗每個站點的值是否已經滿足條件即可,也就是單點查詢。
[CF603E]Pastoral Oddities
原題條件等價於每個連通塊大小為偶數,這裡不證,不是本文重點。
隨著時間推移,答案肯定越來越優,也就是答案具有單調性。維護連通塊肯定是用並查集了。
考慮單次二分答案的演算法。對於時間 \(i\) 的詢問,我們二分一個權值 \(mid\),然後加入所有時間 \(\le i\),權值 \(\le mid\) 的邊,看一下是否所有連通塊都是偶數。
現在變成整體二分。分治存當前處理的時間區間 \([t_l,t_r]\) 和對應答案區間 \([w_l,w_r]\)。
設 \(w_{mid}=\frac{w_l+w_r}2\)。考慮將時間區間拆成兩部分,第一部分的答案在 \([w_{mid}+1,w_r]\) 中,另一部分答案在 \([w_l,w_{mid}]\) 中。
在進入這層分治前用並查集內維護好權值 \(<w_l\) 且時間 \(<t_l\) 的所有邊。現在我們向並查集內加入權值 \(\in[w_l,w_{mid}]\),時間 \(<t_l\) 的邊。
這樣並查集裡就有權值 \(\le w_{mid}\),時間 \(<w_l\) 的邊。這和我們單次二分要求的範圍很類似了,接下來繼續擴充套件:
- 依次加入時間 \(\in[t_l,t_r]\),權值 \(\le w_{mid}\) 的邊,直到滿足所有連通塊都是偶數。
滿足條件就可以停下來了,現在我們找到了一個分界線 \(x\),滿足時間 \(\in[l,x]\) 的都沒辦法只用 \(\le w_{mid}\) 的邊滿足條件,而時間 \(\in[x+1,r]\) 的都能用 \(\le w_{mid}\) 的邊滿足條件。這就說明,時間 \(\in[l,x]\) 的答案都在 \([w_{mid}+1,w_r]\) 中,時間 \(\in[l,x]\) 的答案在 \([w_l,w_{mid}]\) 中。
分治下去即可。注意需要維持進入這層分治前用並查集內維護好權值 \(<w_l\) 且時間 \(<t_l\) 的所有邊。
需要支援並查集的撤銷,用可撤銷的並查集即可。
複雜度會發現每一層加邊的數量加起來都是線性,所以複雜度 \(\Theta(n\log^2n)\)。