rmq:
时间复杂度:O(nlogn)
的时间复杂度,利用动态规划进行预处理,dp[i][j]
, i:代表以i为起点,j:代表 i+(1<<j)-1
的长度,dp[i][j]
代表:[i,i+(1<<j)-1]
区间的最大值,由于区间的合并性质,可以写出所有以 i 为起点 i+(1<<j)-1
长度的区间最大值
查询操作:
查询区间[l,r]
,由于log2(r-l+1)
可能是小数,并不能包含整个[l,r]
区间,所以我们需要查询上下两部分max(dp[l][k],dp[r-(1<<k)+1][k])
,覆盖了[l,r]
区间,值得一提的是,查询操作是O(1)
的复杂度
预处理操作:
void init_rmq()
{
for(int i=1;i<=n;i++)
{
dp[i][0]=a[i];
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)//有效区间
{
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
查询操作:
int rmq(int l,int r)
{
int k=log2(r-l+1);
return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
完整代码:
ST表传送门
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int dp[maxn][32],n,a[maxn];
void init_rmq()
{
for(int i=1;i<=n;i++)
{
dp[i][0]=a[i];
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)//有效区间,代表i后面又i+(1<<j)-1位
{
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int rmq(int l,int r)
{
int k=log2(r-l+1);
return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
int main()
{
int q;
cin>>n>>q;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
init_rmq();
while(q--)
{
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",rmq(l,r));
}
}