RMQ求范围最值(模板)
现在有n个元素的数组a(0),a(1),a(2)…a(n-1),设计一个数据结构,对于每次询问Query(L,R),都可以快速查询a(L),a(L+1)…a(R)的最小值,即min{a(L),a(L+1)…a(R)}
利用动态规划思想,可以做到O(nlogn)预处理,O(1)查询. 预处理时,设dp(i,j)表示从i开始,长度为2^j的一段元素中的最小值,那么状态转移方程是 dp(i,j)=min{dp(i,j-1),dp(i+2^(j-1),j-1)}. 查询时,令k为满足2^k<=R-L+1的最大整数,则查询结果即为min{dp(L,k),dp(R-2^k+1,k)}
#include<bits/stdc++.h>
using namespace std;
const int maxn=100050;
int n; //序列长度
int a[maxn]; //序列,下标[0,n-1]
int Min[maxn][30]; //维护最小值的dp
int Max[maxn][30]; //维护最大值的dp
int MinId[maxn][30];//维护最小值下标(多个最小值,返回最左边的下标)
int MaxId[maxn][30];//维护最大值下标(多个最大值,返回最左边的下标)
void init(){ //建立最值 S-T表 O(nlogn)
for(int i=0;i<n;++i){
Min[i][0]=a[i];
Max[i][0]=a[i];
}
for(int j=1;(1<<j)<=n;++j){
for(int i=0;i+(1<<j)-1<n;++i){
Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ_Min(int L,int R){ //查询区间[L,R]最小值 O(1)
int k=0;
while((1<<(k+1)) <= R-L+1) ++k;
return min(Min[L][k],Min[R-(1<<k)+1][k]);
}
int RMQ_Max(int L,int R){ //查询区间[L,R]最大值 O(1)
int k=0;
while((1<<(k+1)) <= R-L+1) ++k;
return max(Max[L][k],Max[R-(1<<k)+1][k]);
}
void initId(){ //建立最值下标 S-T表 O(nlogn)
for(int i=0;i<n;++i){
MinId[i][0]=i;
MaxId[i][0]=i;
}
for(int j=1;(1<<j)<=n;++j){
for(int i=0;i+(1<<j)-1<n;++i){
int x=a[MinId[i][j-1]],y=a[MinId[i+(1<<(j-1))][j-1]];
if(x<=y)
MinId[i][j]=MinId[i][j-1];
else
MinId[i][j]=MinId[i+(1<<(j-1))][j-1];
x=a[MaxId[i][j-1]],y=a[MaxId[i+(1<<(j-1))][j-1]];
if(x>=y)
MaxId[i][j]=MaxId[i][j-1];
else
MaxId[i][j]=MaxId[i+(1<<(j-1))][j-1];
}
}
}
int RMQ_MinId(int L,int R){ //查询区间[L,R]最小值下标 O(1)
int k=(int)(log((R-L+1)*1.0)/log(2.0));
if(a[MinId[L][k]]<=a[MinId[R-(1<<k)+1][k]])
return MinId[L][k];
else
return MinId[R-(1<<k)+1][k];
}
int RMQ_MaxId(int L,int R){ //查询区间[L,R]最大值下标 O(1)
int k=(int)(log((R-L+1)*1.0)/log(2.0));
if(a[MaxId[L][k]]>=a[MaxId[R-(1<<k)+1][k]])
return MaxId[L][k];
else
return MaxId[R-(1<<k)+1][k];
}
int main(){
while(scanf("%d",&n)==1){
for(int i=0;i<n;++i) scanf("%d",&a[i]);
init();initId();
int q;
scanf("%d",&q);
while(q--){
int le,ri;
scanf("%d%d",&le,&ri);
int minv=RMQ_Min(le,ri);
int minid=RMQ_MinId(le,ri);
int maxv=RMQ_Max(le,ri);
int maxid=RMQ_MaxId(le,ri);
printf("区间[%d,%d]的最小值是%d,下标为%d,最大值是%d,下标为%d\n",le,ri,minv,minid,maxv,maxid);
}
}
return 0;
}