RMQ问题是区间求最值问题,就是求一个数组第i个到第j个中最大数或最小数的算法。
这个算法有一些倍增思想,也有一些二分思想。具体是一个数组,m[i][j]表示从i开始往后数2的j次方个数的最大值或最小值是几。
我们可以很明显的看出,m[i][j]=max(m[i][j-1],m[i+pow(2,j-1)][j-1]);这样就能求出所有i后2的j次方里最大的数了。
但是有一个问题,(可能只有我不会。)如果让查找的区间长度不是2的次方怎么办?我也是想了30分钟。得到了结果,让中间重合一部分,凑成2的log(r-l+1)+1次方。就可以了。
具体操作是max(l开始向后查看2的log(r-l+1)次方,r向前查看2的log(r-l+1)次方),或者min。这样每次运行都是2的次方,也没有多查找。
正经代码来了:
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cmath> #include<cstring> using namespace std; long long m[20][20],mx[20][20],md[20][20],l,r,n,mid,d,x; int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>m[i][0]; mx[i][0]=m[i][0]; md[i][0]=m[i][0]; } for(int j=1;j<=20;j++) { for(int i=1;i+pow(2,j)<=n;i++) { mx[i][j]=min(mx[i][j-1],mx[i+(int)pow(2,(double)j-1)+1][j-1]); md[i][j]=max(md[i][j-1],md[i+(int)pow(2,(double)j-1)+1][j-1]); } } cin>>l>>r; mid=log(r-l+1); d=max(md[l][mid],md[r-(int)pow(2,(double)mid)][mid]); x=max(mx[l][mid],mx[r-(int)pow(2,(double)mid)][mid]); cout<<d<<endl; return 0; }
应该是对的,大家懂了吗,自己试试吧。