用状态 s[i][j] 记录区间长度为 2^j 的长度的区间的最大值
所以状态转移方程就是 st[i][j] = max( st[i][j-1] , st[i+(1 << (j-1))][j-1] )
注意状态转移的方向,保证区间合法性(i+2^j? 不能超过数组大小)
写完这些后,定义好第一个,就可以从前往后进行计算
ST表存储的区间是2的整数倍,所以要计算的是,如何从要求的区间,到ST表存储的区域。
要寻找一个k,如果满足以下的大小关系,
就可以取两个区间的最大值 max(st[l][k],st[r-(1<<k)][k]),这两个区间是囊括了整个要求的区域。
k值的具体计算是,把(r-l+1)对2求对数,并向下取整,可以用强制类型转换来实现。
求区间最大值的代码
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
const int N = 5e5 + 5;
int n,q;
ll a[N];
ll st[N][21];
ll getMax(int l,int r)
{
//计算k,区间长度对2取对数
int k = log(r-l+1)/log(2);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
int main()
{
// 请在此输入您的代码
cin >> n >> q;
for(int i = 1 ; i <= n ; i++)
{
int x;
cin >> x;
a[i] = x;
}
//构造ST表
//1.初始化
for(int i = 1 ; i <= n ; i++) st[i][0] = a[i];
//2.利用状态转移方程求ST表
for(int j = 1 ; j <= 20 ; j++)
{
for(int i = 1 ; i <= n ; i++)
{
if(i + (1<<j) -1 <= n) //不要忘记-1,是要区间长度为 2^j 的
{
st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
}
//3.利用ST表来求区间最大值
while(q--)
{
int l,r;
cin >> l >> r;
cout << getMax(l,r) <<'\n';
}
return 0;
}