对于一类问题:
RMQ(Range Minimum/Maximum Query) 区间最值查询
给一个序列a[1],a[2],…,a[n],每次查询一个区间的最小值
我们可以用线段树解决,也可以一种更简单的数据结构st表来解决
st表相较于线段树而言时间复杂度更低,代码也更简洁
但是st表所能解决的问题非常有限
一句话总结就是:st表能解决的问题线段树一定能解决,但线段是能做到st表做不到
算法实现
运用倍增的思想,我们令(f[i] [k])数组表示区间([i,i + 2^k-1])中的最小值
(f[i] [0]= a[i])
(f[i] [k-1] = min(f[i] [k],f[i + (1<< k)] [k]))
查询时给了一个区间[l, r],我们找一个最大的j满足(2^j <= r - l + 1)
于是我们可以用(f[l] [j])和(f[r – 2^j + 1] [j])来覆盖这个区间,得到最小值
也即(answer = min(f[l] [j], f[r – (1 << j) + 1] [j]))
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,l,r;//这是个st表emm可我不会
int Max[100001][22];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&Max[i][0]);//读入emm他到他本身的区间最大值就是他w
}
for(int j=1;j<=21;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
}
}
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
int a=log2(r-l+1);
printf("%d
",max(Max[l][a],Max[r-(1<<a)+1][a]));
}
return 0;
}