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

iorit發表於2024-03-07

詳細揭秘 整體二分

考慮這樣一個問題:

  • 給你一個序列,每次查詢區間 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)\)