【模板】ST表求解RMQ問題

RMQ 問題

RMQRange Minimum Query ,範圍最小值問題。具體表現爲一下一類問題:

給出一個 n 個元素的數組 A1,A2,,An ,求解 min(l,r) : 計算 min {Al,Al+1,,Ar }

RMQ 問題有很多解法,其中較爲快捷和簡便的是 TarjanSparseTable 算法,簡稱 ST 表。

SparseTable 算法基於倍增思想,整個算法由預處理和查詢兩部分組成,分別描述一下:

  • 預處理

    我們令 d(i,j) 爲從 i 開始的, 長度爲 2j 的一段元素中的最小值。根據倍增思想,d(i,j) 可以通過 d(i,j1)d(i+2j1,j1) 轉移得到,具體操作就是對兩個數取 min

    沒有接觸過倍增思想的同學可能對這步表示有點難以理解,具體解釋一下:

    d(i,j) 表示的是從 i 開始的長度爲 2j 的一段元素中的最小值,區間右端點是 i+2j1

    d(i,j1) 表示的是從 i 開始的長度爲 2j1 的一段元素中的最小值,區間右端點是 i+2j11

    d(i+2j1,j1) 表示的是從 i+2j1 開始的長度爲 2j1 的一段元素中的最小值,區間右端點是 i+2j1+2j11=i+2j1

    現在就明顯了,[i,i+2j1] 這段區間被劃分成了了 [i,i+2j11][i+2j1,i+2j1] 兩段區間,不重不漏,所以這樣操作是可行的。

    預處理的時間複雜度是 O(nlog2n)

  • 查詢

    有了剛纔對預處理的講述,查詢部分應該不難想到,我們令 k 爲滿足 2kRL+1 的最大整數。則可知 k=log2RL+1 。則以 L 開頭, 以 R 結尾的兩個長度爲 2k 的區間合併起來就覆蓋了 [L,R] 。由於是求範圍最小值,有元素被重複計算也沒問題。

    Query(L,R)=min(d(L,k),d(R2k+1,k))

    查詢的時間複雜度是 O(1)

由此可見,SparseTable 算法思想簡單,好寫,是求解 RMQ 問題的首選算法。

具體實現的時候還要注意一點,每次用 pow(2,x) 計算 2x 是非常浪費時間的。由於計算機內部使用的是二進制,我們可以用 (1<<x) 表示 2x

Code

namespace RMQ {     
    void init(int n) {
        for (int i = 1; i <= n; i++) d[i][0] = a[i];
        for (int j = 1; (1 << j) <= n; j++)
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
                d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
    }
    int query(int l, int r) {
        int k = log2(r - l + 1);
        return min(d[l][k], d[r - (1 << k) + 1][k]);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章