【知識點】RMQ問題的ST表實現


$RMQ$問題:給定一個長度為$N$的區間,$M$個詢問,每次詢問$[L_i,R_i]$這段區間元素的最大值/最小值。

$RMQ$的高級寫法一般有兩種,即為線段樹和$ST$表。

本文主要講解一下$ST$表的寫法。(以區間最大值為例)

$ST$表:一種利用$dp$思想求解區間最值的倍增算法。

定義:$f(i,j)$表示$[i,i+2^{j}-1]$這段長度為$2^{j}$的區間中的最大值。

預處理:$f(i,0)=a_i$。即$[i,i]$區間的最大值就是$a_i$。

狀態轉移:將$[i,j]$平均分成兩段,一段為$[i,i+2^{j-1}-1]$,另一段為$[i+2^{j-1},i+2^{j}-1]$。

兩段的長度均為$2^{j-1}$。$f(i,j)$的最大值即這兩段的最大值中的最大值。

得到$f(i,j)=max\{f(i,j-1),f(i+2^{j-1},j-1)\}$。

void RMQ(int N){
    /*注意外部循環從j開始,
    因為初始狀態為f[i][0],
    以i為外層會有一些狀態遍歷不到。*/ 
    for(int j=1;j<=20;j++)  
        for(int i=1;i<=N;i++)
            if(i+(1<<j)-1<=N)
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

 

查詢:若需要查詢的區間為$[i,j]$,則需要找到兩個覆蓋這個閉區間的最小冪區間。

這兩個區間可以重復,因為兩個區間是否相交對區間最值沒有影響。(如下圖)

當然求區間和就肯定不行了。這也就是$RMQ$的限制性。

因為區間的長度為$j-i+1$,所以可以取$k=log_2(j-i+1)$。

則$RMQ(A,i,j)=max\{f(i,k),f(j-2^{k}+1,k)\}$。

 

代碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int a[100001],f[100001][20];
inline int read(){
    int x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}
void RMQ(int N){
    for(int j=1;j<=20;j++)    
        for(int i=1;i<=N;i++)
            if(i+(1<<j)-1<=N)
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 
}
int main(){
    int N=read(),M=read();
    for(int i=1;i<=N;i++) a[i]=read();
    for(int i=1;i<=N;i++) f[i][0]=a[i];
    RMQ(N); 
    while(M--){
        int i=read(),j=read();
         int k=(int)(log((double)(j-i+1))/log(2.0)); 
        printf("%d\n",max(f[i][k],f[j-(1<<k)+1][k]));
    }
    return 0;
}

 


免責聲明!

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



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