问题:
给出一个n个元素的数组,a[1], a[2], …… , a[n],设计一个数据结构,支持查询操作RMQ(L, R),计算min{a[L], a[L+1], …… , a[R]}。
分析:
循环计算会超时,用Tarjan的Sparse-Table算法,预处理时间是O(nlogn),查询只需要O(1)。
令d[i][j]表示从i开始,长度为2的j次方的一段元素的最小值。
则d[i][j] = min(d[i][j-1], d[i+(1<<(j-1)][j-1])。
代码:
#include <cstdio> #include <algorithm> //#include <cmath> using namespace std; const int MAX = 100; int n, a[MAX+10]; int d[MAX+10][MAX+10];//二维应该是floor(log(1.0*MAX)/log(2.0)),但是不知为什么编译有问题。。 int RMQ(int l, int r) { int k = 0; while((1<<(k+1)) <= r-l+1)k++; //也可以k = log(1.0 * r-l+1)/log(2.0); return min(d[l][k], d[r-(1<<k)+1][k]); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= n; i++) d[i][0] = a[i]; for(int j = 1; (1<<j) <= n; j++) for(int i = 1; i+(1<<j)-1 <= n; i++) d[i][j] = min(d[i][j-1], d[i+(1<<(j-1))][j-1]); int l, r; while(scanf("%d %d", &l, &r) != EOF) printf("%d\n", RMQ(l, r)); return 0; }