模板题
ST表 使用了 动态规划 和 倍增 的思想对区间预处理,可以O(1) 解决区间最值查询问题,又称 RMQ,缺点是不支持像线段树那样的点的修改。
f[ i ][ j ] : 代表以 i 为起点,长度为 2^j 的区间的最值
转移方程 : f[ i ][ j ] = max( f[ i ][ j - 1] , f[ i + (1<< (j-1) ) ] [j - 1]) ;
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 2e5+7;
const int M = log(2e5)/log(2)+1; //求区间长度的指数下取整 + 1;
int a[N],n;
int f[N][M]; //含义: 代表以i为起点,长度为2^j 的区间的最值;
void init()
{
for(int j=0;j<M;j++){
for(int i=1;i+(1<<j)-1<=n;i++) //i+len-1 为右端点
if(!j) f[i][j] = a[i]; //边界, 长度为 1 的就是本身
else f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]); //注意这里的括号
}
return ;
}
int query(int l,int r)
{
int len = r-l+1;
int k = log(len)/log(2); //求区间长度的指数下取整
return max(f[l][k],f[r-(1<<k)+1][k]); //一定能覆盖 l ~ r , r-len+1为区间长度为len的左端点;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
init();
int q;
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r)); //区间最值
}
return 0;
}