RMQ算法是一种区间最值查询的方法,运用dp数组来保存区间最值,并通过输入区间获得答案。
RMQ算法。
1.dp数组。RMQ算法在dp数组中采用了数字2的一些机制来对数据进行赋值,dp[i][j]中记录以i为开头往后2^j个数(算自己)中最值,所以最初的状态dp[i][0]就表示a[i]的值(假设a数组来保存所查询数组的值),后面dp数组的赋值就通过(2^k=2^k-1+2^k-1)这样的方式,所以我们知道了dp[i][0]的值我们就能通过式子max(dp[i][j-1],dp[i+2^(j-1)][j-1])=dp[i][j],这样就可以通过dp(i,0)的值得到dp(i,1)的值一直到数据边界。
2.求区间最值。dp数组我们知道了但是dp数组只表示i点到i+2^j -1点之间的最值,而我们要的是l,r区间的最值,所以我们把这个区间分成两个分别求最值,得到两个值再求一下最值。因为dp数组的定义所以我们只能知道区间长度为2的倍数的区间最值,所以我们来求一下,我们最后要找两个能覆盖区间的数,为了方便我们让两个区间长度相同为k,那么我们要求 l+2^k>=r-2^k+1化简的 2^(k+1)>=r-l+2 k>=log2(r-l+1)-1。因为存在log有时不能得到整数所以k=log2(r-k+1)这样我们就得到两个能将l,r覆盖的区间。再把这两个数求最值就完事了。
代码
void rmq_pre()
{
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]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]); //赋值
}
int rmq(int l,int r)
{
int k=log2(r-l+1); //给k值
return min(dp[l][k],dp[r-(1<<k)+1][k]); //返回答案
}