1. 程式人生 > >RMQ問題-ST表倍增處理靜態區間最值

RMQ問題-ST表倍增處理靜態區間最值

get nlogn st表 nbsp char %d 比較 預處理 mat

簡介

ST表是利用倍增思想處理RMQ問題(區間最值問題)的一種工具。 它能夠做到O(nlogn)預處理,O(1)查詢的時間復雜度,效率相當不錯。

算法

1.預處理

ST表利用倍增的思想。以洛谷的P3865作為例子。我們需要查詢某一區間的最大值。 我們用f[ i ][ j ]表示區間i到i+2^j-1的最大值(最小值同理)。在狀態轉移時,我們可以把這個區間拆成兩個區間,分別求最大值。 技術分享圖片 因此,狀態轉移方程為:

f[i][j] = max{ f[i][j-1], f[i+2^(j-1)][j-1] }

2.查詢

查詢也比較簡單。 我們先求出log2(區間長度),令其等於k。 技術分享圖片

然後,我們對左右端點分別查詢(即圖中的綠色線條和紅色線條),保證能夠覆蓋我們需要查詢的整個區間。

為什麽從右端點開始查詢,左端點為r-2^k+1? 其實很簡單,我們需要尋找一個x,使得x+2^k-1=r。所以x=r-2^k+1。

上代碼:

//ST表求靜態區間最大值 洛谷P3865
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int maxn=1e6+10;
int n,m;
int Max[maxn][21
];//Max[i][j]表示區間i到i+2^j-1的最大值 int read() { char ch=getchar(); int f=1;int x=0; while(ch<0||ch>9) { if(ch==-)f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x=x*10+ch-0; ch=getchar(); } return x*f; }
int find(int l,int r) { int k=log2(r-l+1);//計算log2(區間長度) return max(Max[l][k],Max[r-(1<<k)+1][k]); } int main() { n=read();m=read(); for(int i=1;i<=n;i++) { Max[i][0]=read(); } for(int j=1;j<=21;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]); //倍增 //1<<(j-1)表示2^(j-1) } } for(int i=1;i<=m;i++) { int l=read(); int r=read(); printf("%d\n",find(l,r)); } return 0; }

RMQ問題-ST表倍增處理靜態區間最值