RMQ问题,即区间最值问题
tarjan发明的基于倍增的st表算法
可以在
的时间内求解静态RMQ问题
用
表示序列区
内的最值
初始化
那么dp数组就有递推式
即区间
中的最值等于区间
或
中的最值
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]);
当我们查询区间
中的最值时
可以枚举一个断点k
比较区间
和
得到答案
int k=0;
while((1<<k+1)<=rr-ll+1)k++;
ans=max(dp[ll][k],dp[rr-(1<<k)+1][k]);
虽然两个区间可能会重叠,但是这并不影响结果,因为重叠部分也属于
这也是用于比较的第二个区间是
的原因
如果第二个区间是
将有可能越出rr的边界
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
int n,m;
int d[1000010];
int dp[1000010][55];
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
d[i]=read();
for(int i=1;i<=n;i++)
dp[i][0]=d[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]);
while(m--)
{
int ll=read(),rr=read();
int k=0;
while((1<<k+1)<=rr-ll+1)k++;
int ans=max(dp[ll][k],dp[rr-(1<<k)+1][k]);
print(ans);printf("\n");
}
return 0;
}