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\n",max(st[x][z],st[y-(1<<z)+1][z])); } return 0; }