两个比较麻烦的地方:
1.st[i][j] = max(st[i][j-1], st[i+(1<<j-1)][j-1]);
2.ans = max(st[l][k],st[r-(1<<k)+1][k]);
注意i的枚举不要超出上界!!!!!!!
i + (1<<k) - 1 <= n
对于1,st[i][j]表示
[
i
,
i
+
2
j
−
1
]
[i, i+2^j-1]
[i,i+2j−1]区间上的最值,也就是包含
i
i
i的
2
j
2^j
2j个数
对于2,这是可能重叠(也可能刚好相接)的两个区间,比较了一下取最值,第一个区间是
[
l
,
l
+
2
k
−
1
]
[l,l+2^k-1]
[l,l+2k−1],第二个区间是
[
r
−
2
k
+
1
,
r
]
[r-2^k+1,r]
[r−2k+1,r],即“以
r
r
r为结尾的
2
k
2^k
2k个数”,所以左端点是
r
−
2
k
+
1
r-2^k+1
r−2k+1。
然后对于两个取log,第一个取log后要加上1,因为log(n) / log(2) 强转为整型之后是向下取整的,有可能“不够”,要加1
第二个取log不用加1,因为询问时本来就是以区间部分重叠作为代价来方便地查询的
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 100010;
int n,m,a[MAXN],st[MAXN][30];
int main() {
scanf("%d %d", &n, &m);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]),st[i][0] = a[i];
int mt = log(n)/log(2) + 1;
for(int j=1; j<=mt; j++)
for(int i=1; i+(1<<j)-1<=n; i++)
st[i][j] = max(st[i][j-1], st[i+(1<<j-1)][j-1]);
for(int i=1; i<=m; i++) {
int ans = 0;
int l, r;
scanf("%d %d",&l, &r);
int k = log(r-l+1)/log(2);
ans = max(st[l][k],st[r-(1<<k)+1][k]);
printf("%d\n",ans);
}
return 0;
}