令d[i][j]表示从i开始,长度为2^j的一段元素中的最小值,用递推方式计算,d[i][j]=min(d[i][j-1],d[i+2^j-1,j-1),就是将[i,i+2^j]的这段区间一分为二,然后取两段区间的极值就可以了。
2^j小于等于n,所以一般来讲数组第二维开30就够了。
至于递推的计算顺序,j总是与前一项j-1有关,所以对j的循环放在外层,就不会破坏计算顺序。
查询操作就是,令k为满足2^k<=R-L+1的最大整数,则以L,R开头和结尾的两个长度为2^k的区间合并覆盖了L和R的区间
代码的下标从0开始
void RMQ_init(){
for(int i=0;i<n;i++) d[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=0;i+(1<<j)-1<n;i++){
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int L,int R){
int k=0;
while((1<<(k+1))<=R-L+1) k++;
return max(d[L][k],d[R-(1<<k)+1][k]);
}