1. 程式人生 > 其它 >資料結構:ST表——解決RMQ問題

資料結構:ST表——解決RMQ問題

技術標籤:資料結構資料結構演算法

RMQ

RMQ 是英文 Range Maximum/Minimum Query 的縮寫,表示區間最大(最小)值。該類問題的解決方法有ST表,線段樹等。

題目引入

洛谷ST表模板題

題目大意

給定 n n n個數,有 m m m個詢問,對於每個詢問,你需要回答區間 [ l , r ] [l,r] [l,r]中的最大值。

具體實現過程

  1. 預處理部分,令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示區間 [ i , i + 2 j − 1 ] [i,i+2^j-1] [i,i+2j1]的最大值,顯然 d p [ i ] [ 0 ] = a i dp[i][0]=a_i

    dp[i][0]=ai
    第二維相當於倍增時跳了 2 j − 1 2^j-1 2j1步,可將這 2 j − 1 2^j-1 2j1步分成如下兩部分:
    在這裡插入圖片描述
    因此狀態轉移方程可以寫成: d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i + 2 j − 1 ] [ j − 1 ] ) dp[i][j]=max(dp[i][j-1],dp[i+2^{j-1}][j-1]) dp[i][j]=max(dp[i][j1],dp[i+2j1][j1])

  2. 查詢部分,對於每個詢問的區間 [ l , r ] [l,r] [l,r],可以把這個區間分成 [ l , l + 2 s − 1 ] [l,l+2^s-1]

    [l,l+2s1] [ r − 2 s + 1 , r ] [r-2^s+1,r] [r2s+1,r],需滿足 l + 2 s − 1 > = r − 2 s + 1 l+2^s-1>=r-2^s+1 l+2s1>=r2s+1,這樣才能使 [ l , r ] [l,r] [l,r]區間上的最大值是 m a x ( d p [ l ] [ s ] , d p [ r − 2 s + 1 ] [ s ] ) max(dp[l][s],dp[r-2^s+1][s]) max(dp[l][s],dp[r2s+1][s]),所以 s = s= s= ⌊ l o g 2 ( r − l + 1 ) ⌋ \lfloor log_2(r-l+1)\rfloor
    log2(rl+1)
    ,那麼 2 ∗ s 2*s 2s一定大於等於 r − l + 1 r-l+1 rl+1,就保證了這兩個區間能夠覆蓋 [ l , r ] [l,r] [l,r]這個區間。

演算法複雜度

ST 表基於倍增思想,預處理複雜度為 O ( n l o g n ) O(nlogn) O(nlogn),查詢的複雜度為 O ( 1 ) O(1) O(1)

模板程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
int Logn[maxn];
int f[maxn][25];

//int型別資料的快讀
inline int read()
{
    register int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=(x<<3)+(x<<1)+(c^48); 
        c=getchar();
    }
    return x*f;
}

//預處理log2(n)的值
void init()
{
    Logn[1]=0;
    Logn[2]=1;
    for(int i=3;i<maxn;i++){
        Logn[i]=Logn[i/2]+1;
    }
}

int main()
{
//	freopen ("input.txt" , "r" , stdin);
//	freopen ("output.txt" , "w" , stdout);
    int n=read(),m=read();
    for(int i=1;i<=n;i++) f[i][0]=read();
    init();
    //預處理
    for(int j=1;j<=21;j++){
        for(int i=1;i+(1<<j)-1<=n;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    }
    //查詢
    while(m--){
        int l=read(),r=read();
        int s=Logn[r-l+1];
        printf("%d\n",max(f[l][s],f[r-(1<<s)+1][s]));
    }
	return 0;
}

總結

  1. 除 RMQ 以外,“區間按位和”、“區間按位或”、“區間 GCD”,ST 表都能高效地解決。
  2. ST 表能較好的維護“可重複貢獻”的區間資訊(同時也應滿足結合律),時間複雜度較低,程式碼量相對其他演算法很小。但是,ST 表能維護的資訊非常有限,不能較好地擴充套件,並且不支援修改操作