RMQ(Range Minimum/Maximum Query)是一种求区间内最大值或者最小值的算法,这里用st表来实现。
st表首先就是需要倍增算法,以此来降低时间复杂度,那么就先来了解一下倍增算法。众所周知,任何数都能很容易地表示成二进制,倍增就是以2为底数,因此在二进制中表现良好,只需要进行一次位运算的左移就行了。
我们先建立一个数组 s [ i ] [ j ] s[i][j] s[i][j],表示 a [ i ] 到 a [ i + 2 j − 1 ] a[i]到a[i+2^j-1] a[i]到a[i+2j−1]的最值,通过倍增的预处理先将表填满,之后就可以通过 O ( 1 ) O(1) O(1)的操作,直接得到所求值。(虽然在只求值一次的情况下还没有传统的遍历来的快)
建表的过程其实就是dp,而每次的子问题就是 s [ i ] [ j ] 到 s [ i ] [ j − 1 ] s[i][j]到s[i][j-1] s[i][j]到s[i][j−1]之间的最值,毕竟作为质数,差1就是差一倍,这就是表示方便之处。以j为外层循环,i为内层循环,一层一层将表填满。
代码如下:
void RMQ(int n){
for(int i=0;i<n;++i){
s[i][0]=a[i];
}
for(int j=1;j<k;++j){
for(int i=0;i<n;++i){
if(i+(1<<j)-1<=n){
s[i][j]=min(s[i][j-1],s[i+(1<<(j-1))-1][j]);
//s[i][j]=max(s[i][j-1],s[i+(1<<(j-1))-1][j]);
}
}
}
}
st表已经建立好了,剩下的就是 O ( 1 ) O(1) O(1)的查询操作了。
int query(int a,int b){
int tmp=int(log(b-a+1)/log(2));
return s[a][tmp];
}