现在有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;
typedef int type;
const int maxn=1e5+5;
struct RMQ{
int n; //n个元素
type a[maxn]; //序列
type dp[maxn][30];
void init(){//预处理 O(nlogn)
for(int i=0;i<n;++i) dp[i][0]=a[i];
for(int j=1;(1<<j)<=n;++j){
for(int i=0;i+(1<<j)-1<n;++i){
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//最小值
//dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//最大值
}
}
}
type query(int le,int ri){//查询[le,ri]的最值 O(1)
int k=0;
while((1<<(k+1)) <= ri-le+1) ++k;
type ans=min(dp[le][k],dp[ri-(1<<k)+1][k]);//最小值
//type ans=max(dp[le][k],dp[ri-(1<<k)+1][k]);//最大值
return ans;
}
};
int n,q;
RMQ rmq;
int main(){
scanf("%d%d",&n,&q);
rmq.n=n;
rmq.q=q;
for(int i=0;i<n;++i) {
scanf("%d",&rmq.a[i]);
//scanf("%lld",&rmq.a[i]);
}
rmq.init();
while(q--){
int le,ri;
scanf("%d%d",&le,&ri);//[0,n-1]
type ans=rmq.query(le,ri);
printf("%d\n",ans);//printf("%lld\n",ans);
}
return 0;
}