bzoj2724 [Violet 6]蒲公英 分块

2 篇文章 0 订阅

题意:强制在线,求区间众数。
说实话还没有用过除了反演莫队以外的分块。。
具体的话就是分成sqrtn块,然后记录每一块的答案和前缀。
然后询问的时候,如果

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=2e5+5;
typedef long long ll;
const int mx=305;
int ans[mx][mx],n,m,l,r;
int sum[N][mx],cnt[N];
int a[N],b[N],bel[N];
int main()
{
    scanf("%d%d",&n,&m);
    int c=floor(sqrt(n))+1;
    fo(i,1,n)
    {
        scanf("%d",&a[i]);
        bel[i]=(i-1)/c+1;
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    l=unique(b+1,b+n+1)-b-1;
    fo(i,1,n)
    a[i]=lower_bound(b+1,b+l+1,a[i])-b;
    fo(i,1,bel[n])
    {
        int x=0;
        fo(j,(i-1)*c+1,n)
        {
            cnt[a[j]]++;
            if(!x||cnt[a[j]]>cnt[x]||cnt[a[j]]==cnt[x]&&a[j]<x)x=a[j];
            ans[i][bel[j]]=x;
        }
        fo(j,(i-1)*c+1,n)
        if (cnt[a[j]])cnt[a[j]]=0;
    }
    fo(i,1,n)sum[a[i]][bel[i]]++;
    fo(i,1,l)
    fo(j,1,bel[n])
    sum[i][j]+=sum[i][j-1];
    int x=0;
    while (m--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        u=1ll*(u+x-1)%n+1;
        v=1ll*(v+x-1)%n+1;
        if (u>v)swap(u,v);
        int l=bel[u],r=bel[v];
        if (r-l<=1)
        {
            x=0;
            fo(i,u,v)
            {
                cnt[a[i]]++;
                if (!x||cnt[a[i]]>cnt[x]||cnt[a[i]]==cnt[x]&&a[i]<x)x=a[i];
            }
            fo(i,u,v)if (cnt[a[i]])cnt[a[i]]=0;
            x=b[x];
            printf("%d\n",x);
            continue;
        }
        x=ans[l+1][r-1];
        fo(i,u,l*c)
        {
            cnt[a[i]]++;
            if (!x||cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]>cnt[x]+sum[x][r-1]-sum[x][l]||cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]==cnt[x]+sum[x][r-1]-sum[x][l]&&a[i]<x) x=a[i];
        }
        fo(i,(r-1)*c+1,v)
        {
            cnt[a[i]]++;
            if (!x||cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]>cnt[x]+sum[x][r-1]-sum[x][l]||cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]==cnt[x]+sum[x][r-1]-sum[x][l]&&a[i]<x) x=a[i];
        }
        fo(i,u,l*c)
        if (cnt[a[i]])cnt[a[i]]=0;
        fo(i,(r-1)*c+1,v)
        if (cnt[a[i]])cnt[a[i]]=0;
        x=b[x];
        printf("%d\n",x);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值