POJ 3368 RMQ 找区间段出现次数最多的数

给出一个非降序排列的整数数组a1,a2,...an,你的任务是对于一系列询问(i, j),回答ai,ai+1,...aj中出现最多次数的值所出现的次数?

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN =200000+1000;
int dmax[MAXN][20];
int a[MAXN];
int left[MAXN],right[MAXN],num[MAXN];
int d[MAXN];//d[i]=8表第i个不同的值出现了8次
void initmax(int n,int d[])
{
    for(int i=1;i<=n;i++)
        dmax[i][0]=d[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dmax[i][j]=max( dmax[i][j-1],dmax[i+(1<<(j-1))][j-1] );
}
int getmax(int L,int R)
{
    int k=0;
    while(1<<(k+1)<=R-L+1)k++;
    return max(dmax[L][k],dmax[R+1-(1<<k)][k]);
}
int main()
{
    int n,q;
    while(scanf("%d",&n)==1&&n)
    {
        memset(d,0,sizeof(d));
        scanf("%d",&q);
        scanf("%d",&a[1]);
        int cnt=1;//表示当前出现了多少个不同的值
        left[cnt]=1;//第cnt段最左边是位置1
        right[cnt]=1;//第cnt段最右边是位置1
        num[1]=cnt;//第一个元素属于第cnt段
        d[cnt]=1;//第cnt段目前有1个元素
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==a[i-1])
            {
                num[i]=cnt;
                right[cnt]=i;
                d[cnt]++;
            }
            else//出现新值
            {
                num[i]=++cnt;
                left[cnt]=i;
                right[cnt]=i;
                d[cnt]=1;
            }
        }
        initmax(n,d);//注意
        while(q--)
        {
            int L,R;
            scanf("%d%d",&L,&R);
            int num_L=num[L],num_R=num[R];
            if(num_L==num_R)
                printf("%d\n",R-L+1);
            else
            {
                int temp1=right[num[L]]-L+1;//a[L]出现的次数
                int temp2=R-left[num[R]]+1;//a[R]出现的次数
                int temp3=0;
                if(num_R-num_L>1)
                    temp3 = getmax(num_L+1,num_R-1);
                int ans = max(temp3,max(temp1,temp2));
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
</span>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值