【题解】CH4401(bzoj2724)蒲公英 分块+离散化

题目

题目链接
大意:求区间众数

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std; 
const int N=4e4+10;
int n,m,t,len,sz,ans,L,R,cnt,num;
int a[N],b[N],F[N],st[40],ed[40],c[40][40][N],f[40][40],d[40][40];
//c[i][j][k]表示以段边界为端点的区间[i,j]中排名为k的数的出现次数 
//d[i][j]表示i段到j段的众数排名
//f[i][j]表示i段到j段的众数出现次数 
void Init()
{
    t=(int)pow(n*1.0,1.0/3);//每段长度 
    if(t)len=n/t;
    for(int i=1;i<=t;i++)st[i]=(i-1)*len+1,ed[i]=i*len;
    if(ed[t]<n)st[t+1]=ed[t]+1,ed[++t]=n;
    sort(b+1,b+n+1);
    sz=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)F[i]=lower_bound(b+1,b+sz+1,a[i])-b;//离散化去重后储存排名 
    for(int i=1;i<=t;i++)for(int j=i;j<=t;j++)
    {
        for(int k=st[i];k<=ed[j];k++)c[i][j][F[k]]++;
        for(int k=1;k<=sz;k++)
        if(c[i][j][k]>f[i][j]||(c[i][j][k]==f[i][j]&&k<d[i][j]))f[i][j]=c[i][j][k],d[i][j]=k;
    }
}
void update(int i)
{
    c[L][R][F[i]]++;
    if(c[L][R][F[i]]>cnt||(c[L][R][F[i]]==cnt&&F[i]<num))cnt=c[L][R][F[i]],num=F[i];
}
int solve(int x,int y)
{
    int l,r;//起始段终止段 
    if(x>y)swap(x,y);
    for(int i=1;i<=t;i++)if(x<=ed[i]){l=i;break;}
    for(int i=t;i;i--)if(y>=st[i]){r=i;break;}
    if(l+1<=r-1)L=l+1,R=r-1;else L=R=0;
    cnt=f[L][R],num=d[L][R];
    if(l==r)
    {
        for(int i=x;i<=y;i++)update(i);
        for(int i=x;i<=y;i++)c[L][R][F[i]]--;
    }
    else
    {
        for(int i=x;i<=ed[l];i++)update(i);
        for(int i=st[r];i<=y;i++)update(i);//朴素扫描不完整的段 更新答案 
        for(int i=x;i<=ed[l];i++)c[L][R][F[i]]--;
        for(int i=st[r];i<=y;i++)c[L][R][F[i]]--;//数组复原 
    }
    return b[num];
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
    Init();
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        ans=solve((x+ans-1)%n+1,(y+ans-1)%n+1);
        printf("%d\n",ans);
    }
    return 0;
}

总结

因为众数不具有区间可加性,所以用树状数组或者线段树维护就十分困难。我们可以采用分块算法。
把序列a分成T块,每块长度L=N/T
对于每个询问[l,r],设l处于第p块,r处于第q块。把区间[l,r]分成三部分
1.开头不足一整段的[l,L)
2.第p+1~q-1块构成的区间[L,R]
3.结尾不足一整段的(R,r]
a序列在区间[l,r]的众数只可能来自:
1.区间[L,R]的众数
2.出现在[l,L)和(R,r]之间的数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值