ST表是一个用来解决去间最值(RMQ)问题的算法。预处理时间复杂度为O(nlogn),查询复杂度为O(1)。这是一个离线算法,不支持在线修改。
这里洛谷模板为例题讲解,洛谷原题链接:https://www.luogu.org/problemnew/show/P3865
用f[i][j]表示[i,i+2^(j)-1](长度为2^j)这个区间里的最大值。那么如何维护呢?我们可以用二分的思想,[i,i+2^(j)-1]区间的最大值可以由[i,i+2^(j-1)-1]的最大值和[i+2^(j-1)-1,i+2^(j)-1]的最大值得来,所以f[i][j]=max(f[i][j-1],f[i+2^(j-1)-1][j-1])。处理完成之后又要怎么样查询呢?我们可以很容易的想到,当区间长度是2^n的时候,我们可以直接输出。但如果不是的话呢?我们可以画一张图来理解一下:
我们可以算出比区间长度小的最大的2^x,然后通过l往后和从r往前两段区间,求出[l,r]的最大值,那么max[l,r]=max(st[l][x],st[r-(1<<x)+1][x])。
下面是AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,st[100100][20];
int er[100100];
int main(){
register int i,j;
scanf("%d%d",&n,&m);
for(i=1;(1<<i)<=n;++i) er[(1<<i)]=i;
for(i=3;i<=n;++i) if(!er[i]) er[i]=er[i-1];
for(i=1;i<=n;++i) scanf("%d",&st[i][0]);
for(j=1;(1<<j)<=n;++j)
for(i=1;i+(1<<(j-1))<=n;++i)
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
int z=er[y-x+1];
printf("%d
",max(st[x][z],st[y-(1<<z)+1][z]));
}
return 0;
}