區間最值問題(RMQ):壓位分塊稀疏表


區間最值問題(RMQ)也就是給定一個序列 $a[n]$, 多次詢問 $\min a[l:r]$(最大值同理)。

稀疏表

時間復雜度 $O(n\log n)-O(1)$

空間復雜度 $O(n\log n)$

編程難度 低

設 $f(i, j)=\min a[j:2^i+j]$, 遞推預處理。

$$f(i, j)=\begin{cases}a_j,&i=0;\\\min\{f(i-1, j), f(i-1, j+2^{i-1})\},&1 \le i \le \log_2n.\end{cases}$$

在最小值查詢中,一個數被統計多次是沒關系的。因此設 $t=\left\lfloor\log_2(r-l)\right\rfloor$, $\min a[l:r]=\min\{f(t, l), f(t, r-2^t)\}$.

這里特別說一下,保存 $f(i, j)$ 的數組第一維用 $i$, 第二維用 $j$, 可以使遞推時訪存連續,減小時間常數。

RMQ標准算法

時間復雜度 $O(n)-O(1)$

空間復雜度 $O(n)$

編程難度 中等

時空復雜度已達理論下界。可惜常數太大,在數據規模不大的時候有時表現還不如稀疏表。

大致思路是,對序列建笛卡爾樹,RMQ轉成LCA; 對笛卡爾樹求歐拉序,LCA轉成相鄰兩項差值為 $\pm 1$ 的約束RMQ問題。

對於約束RMQ問題,每 $\left\lfloor\frac{\log_2 n}{2}\right\rfloor$ 個分一塊,整塊詢問用稀疏表,塊內詢問由於只有 $O(\sqrt n)$ 種不相似的塊,對於每種都可以遞推預處理塊內任一區間的 RMQ.

壓位分塊稀疏表

時間復雜度 $O(n(1+\log n/\mathrm w))-O(1)$

空間復雜度 $O(n(1+\log n/\mathrm w))$

編程難度 較低

這東西是我校身經百戰,見多識廣的Lagoon隊長告訴我的。我也不知道怎么稱呼,就自作主張,把它叫做“壓位分塊稀疏表”吧。

假設機器字長為 $\newcommand{w}{\mathrm w}\w$, 通常 $\w$ 取值為 $32$ 或 $64$.

考慮一個暴力,詢問按右端點排序,維護所有左端點對應區間的最小值,這是個單調棧就能解決的東西。查詢的時候,最值點就是單調棧上不小於左端點的最左側點。

如果詢問區間長度不超過 $\w$, 那么只需要維護最近 $\w$ 位是否屬於單調棧。形式化地,我們維護一個 $\w$ 比特非負整數 $S_r$, $r-i$ 在單調棧上,當且僅當 $S_r$ 的低第 $i$ 位為 $1$.

計算 $S_r$ 只需要在 $S_{r-1} \mathop{\mathrm{lsh}} 1$ 的基礎上,一邊維護單調棧一邊加刪一些位。因為 $S_r$ 只占一個字長,隨便保存,於是詢問也根本不需要按右端點排序了。

查詢 $\min a[l:r]$, 也就是求 $S_r$ 的低前 $r-l$ 位中,最高位 $1$ 的位置。通過位運算過濾掉太高的位上的 $1$, 然后調用 __builtin_clz(ll) (這是直接調CPU指令的)來查詢最高位。

給序列每 $\mathrm w$ 個分一塊,整塊的部分用稀疏表查詢,塊內用上面這個壓位暴力。

 

模板題:洛谷3865【模板】ST表(區間最大值)代碼鏈接


免責聲明!

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



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