ST 算法类似分块,但分块的大小不一样,ST 表中,第 i 个块大小为 2 i 2^i 2i ,我们用 f [ i ] [ j ] f[i][j] f[i][j] 表示区间 [ i , i + 2 j − 1 ] [i,i+2^j-1] [i,i+2j−1] 的最值,易得 长度为 c c c 的区间 [ l , r ] [l,r] [l,r] 的最值等于 max ( f [ l ] [ log 2 c ] , f [ r − 2 l o g 2 c ] [ l o g 2 c ] ) \max(f[l][\log_2c],f[r-2^{log_2c}][log_2c]) max(f[l][log2c],f[r−2log2c][log2c]) (两个区间有重叠的部分,但是不影响) 这里的 log 都是下取整的, f [ i ] [ j ] = max ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ] ) f[i][j]=\max(f[i][j-1],f[i+2^{j-1}][j-1]) f[i][j]=max(f[i][j−1],f[i+2j−1][j−1]) 于是我们可以用 O ( n log n ) O(n\log n) O(nlogn) 的时间算出 f [ ] [ ] f[][] f[][] ,然后 O ( 1 ) O(1) O(1) 查询,因为 cmath 的 log 效率不高,所以我们也可以预处理, ⌊ log 2 x ⌋ = ⌊ log 2 ⌊ x 2 ⌋ ⌋ + 1 \lfloor \log_2x \rfloor = \lfloor \log_2{\lfloor \frac{x}{2} \rfloor}\rfloor +1 ⌊log2x⌋=⌊log2⌊2x⌋⌋+1
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rp(i, e) for(int i=1;i<=(e);i++)
#define pr(i, e) for(int i=(e);i>=1;i--)
#define rp0(i, e) for(int i=0;i<(e);i++)
#define pr0(i, e) for(int i=(e-1);i>=0;i--)
#define rps(i, b, e) for(int i=(b);i<=(e);i++)
#define prs(i, e, b) for(int i=(e);i>=(b);i--)
#define rpg(i, x) for(int i=head[x];i;i=e[i].nxt)
#define opf(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
using namespace std;
const int NR=1e5+10, CFR=20;
int n, a[NR], f[NR][CFR+5], lg[NR];
//f[i][j]表示a[i~(i+2^j-1)]的最大值
//f[i][j]=max(f[i][j-1], f[i+2^(j-1)][j-1])
//max{[l,r]}=max(f[l][log(r-l)], f[r-2^(log(r-l))+1][log(r-l)])
int main()
{
int T, l, r;
scanf("%d%d", &n, &T);
rp(i, n)scanf("%d", a+i);
rps(i, 2, n)lg[i]=lg[i>>1]+1;
rp(i, n)f[i][0]=a[i];
rp(j, lg[n])
rps(i, 1, n-(1<<j)+1)
f[i][j]=max(f[i][j-1], f[i+(1<<j-1)][j-1]);
while(T--)
{
scanf("%d%d", &l, &r);
printf("%d\n", max(f[l][lg[r-l+!]], f[r-(1<<lg[r-l+1])+1][lg[r-l+1]]));
}
return 0;
}