RMQ 的入門 hdu1806

RMQ(Range Minimum/Maximum Query),即區間最值查詢,是指這樣一個問題:對於長度爲n的數列A,回答若干次詢問RMQ(i,j),返回數列A中下標在區間[i,j]中的最小/大值。ios

這個有不少算法:這裏介紹一種比較高效的ST算法解決這個問題。ST(Sparse Table)算法能夠在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))。數組

代碼:spa

void ST(int n) {
    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 = 0;
    while ((1 << (k + 1)) <= r - l + 1) k++;
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);//int k=(int)(log(double(R-L+1))/log(2.0));
}

查詢是把區間分兩塊,比較得結果。.net

題目:點這裏。code

題意:給出一個非降序的整數數組,你的任務是對於一系列詢問,回答區間內出現最多的值的次數。blog

分析: 非降序,就是說相同的數會連續出現,即就能夠對其分塊,相同的數爲一塊,記錄塊的長度,左右節點。而後就能夠分紅三部分,L在的塊,R在的塊,中間的全部塊,找出中間的最長塊,L,R  在的塊的殘缺值比較,就能夠了,中間的找最長塊就用ST算法。ci

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
const int max_=1e5+5;
int dp[max_][25];//RMQ的數組
int a[max_];//原數組。
int coun[max_];//分段數組
using namespace std;
void RMQ_init(int t)//初始化+遞推
{
    for(int i=1;i<t;i++)
        dp[i][0]=coun[i];
    for(int j=1;(1<<j)<t;j++)
        for(int i=1;i+(1<<j)-1<t;i++)
    {
        dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//int k=(int)(log(double(R-L+1))/log(2.0));
    }
}
int RMQ_Q(int l,int r)//RMQ的查詢
{
    if(l>r)
        return 0;//中間這塊爲0。
    else {
        int k=0;
        while((1<<k+1)<=r-l+1)k++;
        return max(dp[l][k],dp[r-(1<<k)+1][k]);
    }
}

int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0)
            break;
        int m;

        int right[max_],left[max_],num[max_];//每一個段的左右端點,編號。
        int a[max_];
        cin>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
       int k=1,l=1,t=1;//,每段長度,段數
        for(int i=1;i<=n;i++)
        {
             num[i]=t;//編號
            if(a[i]==a[i+1])
            {
                k++;//長度+1;
            }
            else
            {
                right[t]=i;//更新右端點
                left[t]=l;//更新左端點
                l=i+1;
                coun[t]=k;//記錄段的長度
                k=1;
                t=t+1;
            }
        }
       // cout<<t<<endl;
        RMQ_init(t);
        while(m--)
        {
         int l,r;
         cin>>l>>r;
         if(num[l]==num[r])//在同一塊時。
         {
            cout<<r-l+1<<endl;
            continue;
         }
         else//分三塊。
         {
             int L=num[l]+1;
             int R=num[r]-1;
             int temp=RMQ_Q(L,R);
            int res=max(right[L-1]-l+1,max(temp,r-left[R+1]+1));//三塊比較。
            cout<<res<<endl;
         }
        }
    }
}超時,要改爲scanf  和printf……
相關文章
相關標籤/搜索