四毛子算法(Method of Four Russians)的一些簡單應用


與其說四毛子算法(Method of Four Russians)是一種算法不如說它是一種思想,一種(非常規)分塊后暴力預處理以此來優化復雜度的思想。

一類經典的問題是「加一減一 ST 表」:就是現在有一個序列,滿足其差分序列只有 +1 和 -1,如何快速維護區間最小值?我們的做法是,先按照 \(B=\lceil\frac{\log_2 n}{2}\rceil\) 分塊,那么我們現在有 \(\lceil n/B\rceil\) 個塊,只要我們能快速維護出塊內每個子區間的最小值,就可以用 ST 表在 \(\mathcal{O}(\frac{n}{B}\log\frac{n}{B})=\mathcal{O}(n)\) 的復雜度內完成預處理。那么現在注意到塊內的不同可能序列的個數最多只有 \(\mathcal{O}(2^B)=\mathcal{O}(\sqrt n)\) 種,於是可以預處理出每種可能的序列的每個子區間最小值所在位置,這樣就可以做到 \(\mathcal{O}(n)-\mathcal{O}(1)\) 查詢。

現在來看一個進階版的:如何 \(\mathcal{O}(n)-\mathcal{O}(1)\) 查詢樹上兩點的 LCA?一個做法是,先求出整棵樹的(擴展)歐拉序,也就是不只是在退出一個點的時候記錄,而是每次訪問一條邊就記錄兩個端點。這樣容易證明從一個點的第一個位置到另一個點的第一個位置中間的深度最淺的點就是它倆的 LCA,於是轉化為了 RMQ 問題,而注意到這也是一個「加一減一 ST 表」,於是優化到了 \(\mathcal{O}(n)-\mathcal{O}(1)\)

終極進階版:如何 \(\mathcal{O}(n)-\mathcal{O}(1)\) 求一個任意序列的 RMQ?先對這個序列建出笛卡爾樹,於是就轉化為了 LCA 問題,這是我們已經會做了的。


另一種問題是,求一張有向圖的傳遞閉包。或者更普適一些:快速求兩個 01 矩陣的積,其中加法定義為或運算,乘法定義為與運算。

不妨假定都是 \(n\times n\) 的方陣,於是設分塊大小為 \(B=\lceil\log_2 n\rceil\),然后做如下操作:將 A 划分成 \(\lceil \frac nB\rceil\) 個橫條(不足填零),將 B 划分成 \(\lceil \frac nB\rceil\) 個縱條,然后把對應的橫條和縱條做乘積,得到 \(\lceil\frac nB\rceil\)\(n\times n\) 的方陣。那么我們有結論,這兩個方陣的乘積就是所有結果加起來的和。

那么我們現在來考慮優化:對於某兩條的乘法,我們可以先預處理出 A 的橫條中的某一列是某種情況(共 \(2^B=\mathcal{O}(n)\) 種)時,B 的縱條對結果的貢獻(就是結果的某一列),然后每次只用累加這個結果就行了,總復雜度降到了 \(\mathcal{O}(\frac{n^3}{\log n})\).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM