1. 程式人生 > >UVa 11235 頻繁出現的數值

UVa 11235 頻繁出現的數值

劉汝佳書上看到的問題,沒有看題解做了一下,直接AC了,不多說了,直接上程式碼總的來說RMQ查詢左部最大,右部最大,和交叉部最大的三者中的最大值

#include <utility>
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
map<int, pair<int,int>>mmp;
int v[100005][20],vv[100005];
int n,q;
void m_build(){
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++){
            int t=0;
            if(vv[i+(1<<(j-1))-1]==vv[i+(1<<(j-1))])
                t=min(mmp[vv[i+(1<<(j-1))-1]].second,i-1+(1<<j))-max(mmp[vv[i+(1<<(j-1))-1]].first,i)+1;
            v[i][j]=max(t,max(v[i][j-1],v[i+(1<<(j-1))][j-1]));
        }
}
int m_find(int l,int r){
    int k=0;
    while((1<<(k+1))<=r-l+1)k++;
    int t=0;
    if(vv[r-(1<<k)+1]==vv[l+(1<<k)-1])
        t=min(r,mmp[vv[r-(1<<k)+1]].second)-max(l,mmp[vv[r-(1<<k)+1]].first)+1;
    return max(t,max(v[l][k],v[r-(1<<k)+1][k]));
}
int main() {
    while (scanf("%d",&n)!=EOF) {
        if(n==0)
            break;
        scanf("%d",&q);
        for(int i=1;i<=n;i++)
            v[i][0]=1;
        int s=1;
        scanf("%d",&vv[1]);
        for(int i=2;i<=n;i++){
            scanf("%d",&vv[i]);
            if(vv[i]!=vv[i-1]){
                pair<int, int>x;
                x.first=i-s;
                x.second=i-1;
                mmp[vv[i-1]]=x;
                s=1;
            }
            else
                s++;
        }
        pair<int, int>x;
        x.first=n-s+1;
        x.second=n;
        mmp[vv[n]]=x;
        m_build();
        while (q--) {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",m_find(l,r));
        }
    }
    return 0;
}