原网址:http://blog.sina.com.cn/s/blog_6e63f59e0101598a.html
关于RMQ的ST算法,以前也大略上看过,也写过程序,可是后来时间长了就忘记了,今天再看到,觉得并没有以前觉得的那么难理解。唉。毕竟以前弱。虽然现在也蒟蒻。
ST算法的原理就是,nlogn预处理出Min[][]和Max[][],查询的时候O(1)查询。
Max[j][i]或Min[j][i]代表,从j的位置开始,长度为2^i的子段中的最大值或最小值。
然后预处理的时候递推。
询问的时候先算出[l,r]的长度的2的对数,然后取出答案即可。
下面贴代码,程序中Min[][],Max[][]存的是最小值最大值的位置,如果这个区间有两个最小值,则保留靠左的那个。查询的时候,若q为0代表查询最小值,q为1代表查询最大值。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
#define mx 100010
int Min[mx][20],Max[mx][20],n,m,a[mx];
void makermq(){
for (int i = 1;i <= n;i ++) Min[i][0] = Max[i][0] = i;
for (int i = 1;(1 << i) <= n;i ++){
for(int j = 1;j + (1 << i) - 1 <= n;j ++){
int p = Min[j][i - 1],q = Min[j + (1 << i - 1)][i - 1];
if (a[p] < a[q] || (a[p] == a[q] && p < q)) Min[j][i] = p;
else Min[j][i] = q;
p = Max[j][i - 1],q = Max[j + (1 << i - 1)][i - 1];
if (a[p] > a[q] || (a[p] == a[q] && p < q)) Max[j][i] = p;
else Max[j][i] = q;
}
}
}
int ask(int l,int r,int q){
int tmp = int(log(r - l + 1) / log(2));
int k1,k2;
if (q == 0){
k1 = Min[l][tmp],k2 = Min[r - (1 << tmp) + 1][tmp];
if (a[k1] < a[k2] || (a[k1] == a[k2] && k1 < k2)) return k1;
else return k2;
}
else{
k1 = Max[l][tmp],k2 = Max[r - (1 << tmp) + 1][tmp];
if (a[k1] > a[k2] || (a[k1] == a[k2] && k1 < k2)) return k1;
else return k2;
}
}
int main(){
cin >> n >> m;
for (int i = 1;i <= n;i ++) cin >> a[i];
makermq();
int l,r,q;
for (int i = 1;i <= m;i ++){
cin >> l >> r >> q;
cout << ask(l,r,q) << endl;
}
}