BZOJ 2724 [Violet 6]蒲公英

【题目分析】
区间众数,分块+前缀和


【代码】

#include <cmath> 
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[40010],b[40010],L[40],R[40],buk[40][40][40010],mo[40][40];
int now[40010],lst[40010];
int ans=0,cnt=0,T,tot,l,r;
inline int read()
{
    int ret=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9')
    {
        ret*=10;
        ret+=ch-'0';
        ch=getchar();
    }
    return ret*f;
}
int main()
{
    int n,m; n=read();m=read();
//  printf("%d %d\n",n,m);
    for (int i=1;i<=n;++i) a[i]=read(),b[i]=a[i];
    sort(b+1,b+n+1); cnt=unique(b+1,b+n+1)-b-1;
    for (int i=1;i<=n;++i)
        a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
    T=pow(n+0.1,2.0/3); tot=pow(n,1.0/3);
    for (int i=1;i<=tot;++i)
    {
        L[i]=R[i-1]+1;
        R[i]=(i==tot)?n:L[i-1]+T-1;
    }
//  for (int i=1;i<=tot;++i) printf("%d ",L[i]); puts("");
//  for (int i=1;i<=tot;++i) printf("%d ",R[i]); puts("");
    for (int i=1;i<=tot;++i)
    {
        for (int j=L[i];j<=R[i];++j)
            buk[i][i][a[j]]++;
        for (int j=1;j<=cnt;++j)
            if (buk[i][i][j]>buk[i][i][mo[i][i]])
                mo[i][j]=j;
    }
    for (int i=tot;i;--i)
        for (int j=i+1;j<=tot;++j)
            for (int k=1;k<=cnt;++k)
            {
                buk[i][j][k]=buk[i][i][k]+buk[i+1][j][k];
                if (buk[i][j][k]>buk[i][j][mo[i][j]])
                    mo[i][j]=k;
            }
    for (int k=1;k<=m;++k)
    {
        scanf("%d%d",&l,&r);
        l=(l+ans-1)%n+1; r=(r+ans-1)%n+1;
        if (l>r) swap(l,r);
//      printf("%d %d\n",l,r);
        int ll=1,rr=tot;
        while (ll<=tot&&L[ll]<l) ll++;
        while (rr&&R[rr]>r) rr--;
        if (ll>rr)
        {
            ans=0;
            for (int i=l;i<=r;++i)
            {
                if (lst[a[i]]<k)
                {
                    lst[a[i]]=k;
                    now[a[i]]=1;
                }
                else now[a[i]]++;
                if (now[a[i]]>now[ans]||
                (now[a[i]]==now[ans]&&a[i]<ans))
                    ans=a[i];
            }
            ans=b[ans];
            printf("%d\n",ans);
            continue;
        }
        ans=mo[ll][rr];
        lst[ans]=k;
        now[ans]=buk[ll][rr][ans];
        for (int i=l;i<L[ll];++i)
        {
            if (lst[a[i]]<k)
            {
                lst[a[i]]=k;
                now[a[i]]=buk[ll][rr][a[i]]+1;
            }
            else now[a[i]]++;
            if (now[a[i]]>now[ans]||
            (now[a[i]]==now[ans]&&a[i]<ans))
                ans=a[i];
        }
        for (int i=R[rr]+1;i<=r;++i)
        {
            if (lst[a[i]]<k)
            {
                lst[a[i]]=k;
                now[a[i]]=buk[ll][rr][a[i]]+1;
            }
            else now[a[i]]++;
            if (now[a[i]]>now[ans]||
            (now[a[i]]==now[ans]&&a[i]<ans))
                ans=a[i];
        }
        ans=b[ans];
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值