(RMQ)Range Minimum/Maximum Query區間最值問題算法

RMQ適用范圍:給定區間,求最值。


RMQ最大值圖示

預處理(構造):
對于第0行:存取范圍為j~j的數字(本身)
對于第1行:存取范圍為j~j+2^i-1的最大值(范圍為2)
dp[i][j]=max(dp[i-1][j],dp[i-1][j+(2^(i-1))])
對于第2行:存取范圍為j~j+2^i-1的最大值(范圍為4)
dp[i][j]=max(dp[i-1][j],dp[i-1][j+(2^(i-1))])
對于第3行:存取范圍為j~j+2^i-1的最大值(范圍為8)
dp[i][j]=max(dp[i-1][j],dp[i-1][j+(2^(i-1))])

void RMQ(int n)
{
    int i, j;
    for(i=1; (1<<i)<=n; i++)
    {
        for(j=1; (j+(1<<(i-1)))<=n; j++)
        {
            dp[i][j]=max(dp[i-1][j],dp[i-1][j+(1<<(i-1))]);
        }
    }
}

詢問:

int Find(int l, int r)
{
    int k=0;
    while((1<<(k+1)) <= (r-l+1)) k++;
    return max(dp[k][l],dp[k][r-(1<<k)+1]);
}

例題:https://vjudge.net/contest/160175#problem/O
輸入n個數字,m個詢問,每個詢問給定區域l,r輸出該區域的最小值。

#include<cstdio>
#include<algorithm>
using namespace std;

int dp[21][1000005];
void RMQ(int n)
{
    int i, j;
    for(i=1; (1<<i)<=n; i++)
    {
        for(j=1; (j+(1<<(i-1)))<=n; j++)
        {
            dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<(i-1))]);
        }
    }
}

int Find(int l, int r)
{
    int k=0;
    while((1<<(k+1)) <= (r-l+1)) k++;
    return min(dp[k][l],dp[k][r-(1<<k)+1]);
}

int main()
{
    int i, n, m, l, r;
    scanf("%d", &n);
    for(i=1; i<=n; i++)
        scanf("%d", &dp[0][i]);
    RMQ(n);
    scanf("%d", &m);
    for(i=1; i<=m; i++)
    {
        scanf("%d%d", &l, &r);
        printf("%d\n", Find(l, r));
    }
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容