ST表讲解

ST表主要用于解决RMQ问题(区间最值问题)
当然你可以用线段树等,但今天用一种ST表(倍增算法)

ST表是倍增算法的一个典型应用
暴力做RMQ问题,往往会超时,ST表利用对其进行优化

给定一段序列A,ST算法能在O(NlogN)的时间预处理后,以O(1) 的复杂度查询,在线回答在一段区间l,r 中最大(小)值是多少。

f[i][j]用于表示在序列a中, 从第i位数字往后数2j个数,这个区间内的最大值,即区间[ i , i + 2 j ]内取得的最大值。

而这段区域的最大值等于左右子区间的最大值,2j = 2 * 2 j-1 = 2j-1 + 2j-1,把区间[i,i+2j]分成[i , i + 2j-1 ] [ i + 2j-1 + 1,2j]
(即f [ i ] [ j - 1 ] 与 f [ i + 2 j-1 - 1 ] [ j -1 ] )

我们可得:F [ i ] [ j ] = max ( F [ i ] [ j - 1 ] , F [ i + 2 j-1 - 1 ] [ j - 1 ] )
递推边界为f[i][0]=a[i]

其实说白了就是:相求大区间就先求出小区间,求小区间就求小小区间,一直这样套娃到最低层。

但是我们查询的区间不一定总是2的倍数,也有可能会超出区间
所以我们询问区间[l,r]时要用一个k,k=log2(len),len为区间的长度,k向下取整
len=r-l+1
2t<len<2t+1
左右区间最大值分别是F [ l , k ] 与F [ r - 2k + 1 , k ]

#include<cstdio>
#include<iostream>
#include<cmath>

using namespace std;

long f[100001][40];
int n,m;

void ST()//预处理
{
    for(int k=1;k<=(int)log2(n);k++){
        for(int i=1;i<=n-(1<<k)+1;i++){
            f[i][k]=max(f[i][k-1],f[i+(1<<(k-1))][k-1]);
        }
    }
}
int query(int l,int r)//查询
{
        int k=log2(r-l+1);
        return max(f[l][k],f[r-(1<<k)+1][k]);

}
int a[100];
int main(){
    cin>>n>>m;
    
    int temp;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        
        f[i][0]=a[i];
    }

    int l,r;
    for(int i=1;i<=m;i++){
    scanf("%d%d",&l,&r);
    cout<<query(l,r);
    }
	
    return 0;
}


posted @ 2020-04-20 16:20  回归梦想  阅读(117)  评论(0编辑  收藏  举报