ST表(求解静态RMQ问题)

例题:https://www.acwing.com/problem/content/1272/

ST表类似于dp。

定义st[i][j]表示以i为起点,长度位2^j的一段区间,即[ i , i + 2^j - 1 ]。

而这个区间又可以被拆分为[i,i+2^(j-1)-1]+[ i + 2 ^ ( j - 1 ) , i + 2 ^ j - 1 ]这两个区间可以这样表示st[i][j-1]和st[i+(1<<(j-1))][j-1]

所以

st[i][j] = m(st[i][j-1],st[i+(1<<(j-1))][j-1]);

然后枚举长度和端点就可以以O(nlogn)转移状态了。特别的st[i][0]=arr[i]

查询:

设查询区间为[x,y]。将[x,y]分为两个带有重叠的子区间即[x,k1]+[k2,y]。其中k1>=k2。

怎样拆分呢?取log(y-x)向下取整,设为k,将[x,y]分为[x,x+2^k-1]+[y-2^k+1,y]。

我们可以做一下差即y-2^k+1-x-2^k+1=y-x-2^(k+1)+2。 结果一定是小于等于0的。

所以答案为:

m(st[x][k],st[y-(1<<k)+1][k])

 例题code:

#include<bits/stdc++.h>
using namespace std;
const int N = 1E5 + 7;
int st[N][40];
int n,m;
int Log[N];
int arr[N]; 
void ST(){
//    Log[1] = 0;//预处理log函数  
//    for(int i = 2;i <= n+1;i++) Log[i] = Log[i/2]+1;
    for(int i = 1;i <= n;i++) st[i][0] = arr[i];
    
    for(int j = 1; (1<<j) <= n;j++){ 
        for(int i = 1;i + (1<<(j-1)) <= n;i++){
            st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        }
    }
} 
int main(){
    inint();
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>arr[i];
    ST(); 
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        int k= Log[y-x+1];
        cout<<max(st[x][k],st[y-(1<<k)+1][k])<<endl;
    }
    return 0;
}

 记录一个求O(n)求log的方法

log[i]=log[i/2]+1   当i刚好的i的倍数时,想当然log[i]=log[i/2]+1。

        当i不是i的倍数时,i/2刚好舍去余数,向下取整。。。秒~~

原文地址:https://www.cnblogs.com/Accepting/p/12577784.html