UVA 11235-Frequent values(RMQ)

kewlgrl發表於2016-08-08
Frequent values

題目意思:

給出一個非降序排列的整數陣列A,對於一系列詢問(L,R),求出AL~AR區間內出現次數最多的值出現的次數。

解題思路:

陣列非降序,所以對整個陣列進行遊程編碼。

所求的最大值是以下三個部分的最大值:

①從L到L所在的段的結束處的元素個數:right[L]-L+1

②從R到R所在的段的開始處的元素個數:R-left[R]+1

③中間第num[L]+1段到第num[R]-1段的cnt的最大值(RMQ)

注意!!這題輸入輸出要用C風格,C++會RE…Orz


#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define maxn 100100
#define ll long long
using namespace std;
int n,m;
int a[maxn],d[maxn][50];//給定的陣列個RMQ用的DP陣列
int value[maxn],cnt[maxn];//第i段的數值和出現次數
int num[maxn],lefts[maxn],rights[maxn];//當前下標表示的位置的所在段的編號和左右端點的位置
void RMQ_init()
{
    int i,j;
    for(i=1; i<=n; i++)
        d[i][0]=cnt[i];
    for(j=1; (1<<j)<=n; j++)
        for(i=1; i+(1<<j)-1<=n; i++)
            d[i][j]=max(d[i][j-1],d[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(d[l][k],d[r-(1<<k)+1][k]);
}


int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("G:/x/read.txt","r",stdin);
    freopen("G:/x/out.txt","w",stdout);
#endif
    int q,i,m=1,l,ans=-1;
    bool flag=false;
    while(scanf("%d",&n),n)
    {
        scanf("%d",&q);
        memset(a,0,sizeof(a));
        memset(value,0,sizeof(value));
        memset(cnt,0,sizeof(cnt));
        memset(num,0,sizeof(num));
        memset(lefts,0,sizeof(lefts));
        memset(rights,0,sizeof(rights));
        memset(d,0,sizeof(d));
        for(i=1; i<=n; ++i)
        {
            scanf("%d",&a[i]);
            if(a[i]!=a[i-1]&&i!=1) flag=true;
            if(i==1)//a[1]特判一下
            {
                value[m]=a[i];
                ++cnt[m];
                num[i]=m;
                lefts[i]=i;
                l=i;
            }
            if(flag&&i!=1)
            {
                lefts[i]=i;
                l=i;
                ++m;
                num[i]=m;
                value[m]=a[i];
                ++cnt[m];
                for(int k=lefts[i-1]; k<i; ++k)
                    rights[k]=i-1;
                flag=false;
            }
            else
            {
                if(i!=1)
                {
                    ++cnt[m];
                    num[i]=m;
                    lefts[i]=l;
                    value[m]=a[i];
                }
                if(i==n)
                    for(int k=lefts[i-1]; k<=i; ++k)
                        rights[k]=i;
            }
        }
        RMQ_init();
        for(i=0; i<q; ++i)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if(num[l]==num[r])  printf("%d\n",r-l+1);//特判,如果L和R在同一段中
            else
            {
                ans=max((rights[l]-l+1),(r-lefts[r]+1));
                if(num[l]+1<=num[r]-1)//必須保證RMQ區間左端點小於右端點
                {
                    int res=RMQ(num[l]+1,num[r]-1);
                    ans=max(ans,res);
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
/**
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
**/



相關文章