其他分享
首页 > 其他分享> > 洛谷P4168 [Violet]蒲公英(分块)

洛谷P4168 [Violet]蒲公英(分块)

作者:互联网

https://www.luogu.com.cn/problem/P4168

 

分块大法好

首先离散化把值域缩小到n

预处理3个数组

sum[i][j]表示前i块里j的出现次数

mx[i][j]表示第i块到第j块出现次数最多的数出现了多少次

who[i][j]表示第i块到第j块出现次数最多的数最小是谁

对于查询

如果左右端点在同一块或者相邻,就暴力求

如果左右端点所在块中间至少隔着一块,

假设左端点在第bl块,右端点在br块

先直接通过mx和who获取bl+1到br-1块中出现次数最多的最小的数及出现次数

然后只考虑在bl块里左端点后面的,以及在br块里右端点前面的数

枚举这些数,先用一个数组记录在bl+1到br-1块中出现的次数

然后再对他们累加左右端点所在块的出现次数,更新答案

 

#include<bits/stdc++.h>

using namespace std;

#define N 50002

int a[N],ha[N];

int sum[251][N];
int mx[251][251],who[251][251];

int tmp[N];

int main()
{
    //freopen("P4168_1.in","r",stdin);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) 
    {
        scanf("%d",&a[i]); 
        ha[i]=a[i];
    }
    sort(ha+1,ha+n+1);
    int nn=unique(ha+1,ha+n+1)-ha-1;
    for(int i=1;i<=n;++i) a[i]=lower_bound(ha+1,ha+nn+1,a[i])-ha;
    int siz=sqrt(n),s=(n-1)/siz+1,rr,rr2;
    for(int i=1;i<=s;++i)
    {
        for(int j=1;j<=nn;++j) 
        {
            sum[i][j]=sum[i-1][j];
            tmp[j]=0;
        }
        for(int j=1;j<i;++j)
        {
            mx[j][i]=mx[j][i-1];
            who[j][i]=who[j][i-1];
        }
        rr=min(n,i*siz);
        for(int j=(i-1)*siz+1;j<=rr;++j) 
        {
            sum[i][a[j]]++;
            for(int k=1;k<=i;++k)
            {
                rr2=siz*k;
                if(sum[i][a[j]]-sum[k-1][a[j]]>mx[k][i] || sum[i][a[j]]-sum[k-1][a[j]]==mx[k][i] && a[j]<who[k][i])
                {
                    mx[k][i]=sum[i][a[j]]-sum[k-1][a[j]];
                    who[k][i]=a[j];
                }
            }
        }
    }
    int l,r,bl,br,amx,awho,last=0;
    while(m--)
    {
        scanf("%d%d",&l,&r);
        l=(l+last-1)%n+1;
        r=(r+last-1)%n+1;
        if(l>r) swap(l,r); 
        bl=(l-1)/siz+1;
        br=(r-1)/siz+1;
        if(bl+1>=br)
        {
            amx=0;
            for(int i=l;i<=r;++i) tmp[a[i]]=0;    
            for(int i=l;i<=r;++i) 
            {
                tmp[a[i]]++;
                if(tmp[a[i]]>amx || tmp[a[i]]==amx && a[i]<awho)
                {
                    amx=tmp[a[i]];
                    awho=a[i];
                }
            }                    
        }
        else
        {
            amx=mx[bl+1][br-1];
            awho=who[bl+1][br-1];
            rr=bl*siz;
            rr2=(br-1)*siz+1;
            for(int i=l;i<=rr;++i) tmp[a[i]]=sum[br-1][a[i]]-sum[bl][a[i]];
            for(int i=rr2;i<=r;++i) tmp[a[i]]=sum[br-1][a[i]]-sum[bl][a[i]];
            for(int i=l;i<=rr;++i) 
            {
                tmp[a[i]]++;
                if(tmp[a[i]]>amx || tmp[a[i]]==amx && a[i]<awho)
                {
                    amx=tmp[a[i]];
                    awho=a[i];
                }
            }
            for(int i=rr2;i<=r;++i) 
            {
                tmp[a[i]]++;
                if(tmp[a[i]]>amx || tmp[a[i]]==amx && a[i]<awho)
                {
                    amx=tmp[a[i]];
                    awho=a[i];
                }
            }
        }
        last=ha[awho];
        printf("%d\n",last);
    }
}

 

标签:洛谷,br,amx,int,bl,端点,Violet,251,P4168
来源: https://www.cnblogs.com/TheRoadToTheGold/p/15158080.html