UVA 11235 - Frequent values(预处理+RMQ)

题目链接 https://cn.vjudge.net/problem/UVA-11235

【题意】
给定一个非降序排列的整数数组a(1),a(2)…a(n),你的任务是对于一系列询问(i,j),回答a(i),a(i+1)…a(j)中出现次数最多的值所出现的次数

【输入格式】
多组输入,第一行为两个整数n,q(1<=n,q<=1e5),第二行包含n个非降序排列的整数a(1),a(2)…a(n)(-1e5<=a(i)<=1e5)以下q行每行两个数i,j(1<=i<=j<=n),当n=0时输入结束

【输出格式】
对于每组查询输出出现最多的次数值

【思路】
预处理+RMQ,预处理时,注意到所有的元素是非降序的,所有相等的元素会聚集在一起,可以把整个数组进行游程编码,将若干相同元素看作一段,v[i],cnt[i]表示第i段的元素值为v[i],共有cnt[i]个这样的元素,同时对于原序列,我们还可以预处理出num[p],每个位置对应的段编号;left[i],right[i],每个段的左右端点在原序列中的位置。这样对于每次查询(le,ri),答案就从三个部分找,一个是从le到le所在段的结束,一个是ri所在段的开始到ri,还有就是从num[le]+1到num[ri]-1段中cnt的最大值,注意当ri和le在同一段中时,答案就是ri-le+1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=1e5+50;

int n,m,q;
int a[maxn<<1];
int num[maxn],v[maxn],cnt[maxn];
int L[maxn],R[maxn];
int dp[maxn][50];

void RMQ_init(){
    for(int i=0;i<m;++i) dp[i][0]=cnt[i];
    for(int j=1;(1<<j)<=m;++j){
        for(int i=0;i+(1<<j)-1<m;++i){
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
}

int RMQ(int le,int ri){
    int k=0;
    while((1<<(k+1))<=ri-le+1) ++k;
    return max(dp[le][k],dp[ri-(1<<k)+1][k]);
}

int main(){
    while(scanf("%d",&n)==1 && n){
        m=0;
        memset(a,0,sizeof(a));

        scanf("%d",&q);
        for(int i=0;i<n;++i){
            int x;
            scanf("%d",&x);
            x+=1e5;
            ++a[x];
        }

        int s=0;
        for(int i=0;i<=2e5;++i){
            if(a[i]==0) continue;
            v[m]=i;
            cnt[m]=a[i];
            L[m]=s;
            R[m]=s+a[i]-1;
            for(int j=L[m];j<=R[m];++j) num[j]=m;

            s+=a[i];
            ++m;
        }

        RMQ_init();

        while(q--){
            int le,ri;
            scanf("%d%d",&le,&ri);
            --le,--ri;
            if(num[le]==num[ri]){
                printf("%d\n",ri-le+1);
            }
            else{
                int ans=max(R[num[le]]-le+1,ri-L[num[ri]]+1);
                if(num[le]+1<=num[ri]-1){
                    ans=max(ans,RMQ(num[le]+1,num[ri]-1));
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiao_k666/article/details/80530625