洛谷4168 BZOJ2724 蒲公英 分块+离散化

题目链接
题意:
给你一个n个数,有m次询问,每次询问一个区间内最小的众数是多少,强制在线。

题解:
这种东西想想也感觉线段树之类的很难维护,所以就用相对更暴力、功能更强的分块。

具体做法:
由于每个数的值域是 [ 0 , 10 9 ] ,所以要先离散化一下。然后我们对下标分成 n 块,我们首先考虑维护众数,我们知道,对于整块的众数,我们可以预处理出来,但是对于在块外的部分,只有在块外出现的这些数才可能加上整块里的比原来只考虑整块的答案大,所以记录哪些数字是在块外出现了的,然后每个数在每一整块内出现的次数可以用前缀和预处理出来,所以每次只需要处理 O ( n ) 级别的那些在块外的数就可以了。至于还要满足最小,那么就记录离散化后的每一种数出现了多少次和当前出现次数最多的数离散化后的值,更新答案时不仅是在有一个数比当前众数出现次数更多时更新,还要在有一个数与当前众数出现次数一样但是数值比当前众数更小的情况更新。
最后总的复杂度就是 O ( m n )
代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,pos[50010],sz,lastans,t[50010],a[50010],cur,ji[50010];
int cnt[50010][300],f[300][300],shu,bl[50010],br[50010],ci[50010];
inline int query(int l,int r)
{
    int tot=0,ans=0,val=0;
    if(pos[l]==pos[r]||pos[l]+1==pos[r])
    {
        for(int i=l;i<=r;++i)
        ci[a[i]]=0;
        for(int i=l;i<=r;++i)
        {
            ++ci[a[i]];
            if(ci[a[i]]>ci[ans]||(ci[a[i]]==ci[ans]&&a[i]<ans))
            ans=a[i];
        }
    }
    else
    {
        ans=f[pos[l]+1][pos[r]-1];
        val=cnt[ans][pos[r]-1]-cnt[ans][pos[l]];
        for(int i=l;i<=br[pos[l]];++i)
        ji[++tot]=a[i];
        for(int i=bl[pos[r]];i<=r;++i)
        ji[++tot]=a[i];
        for(int i=1;i<=tot;++i)
        ci[ji[i]]=cnt[ji[i]][pos[r]-1]-cnt[ji[i]][pos[l]];
        for(int i=1;i<=tot;++i)
        ++ci[ji[i]];
        for(int i=1;i<=tot;++i)
        {
            if(ci[ji[i]]>val||(ci[ji[i]]==val&&ji[i]<ans))
            {
                ans=ji[i];
                val=ci[ji[i]];
            }
        }
        for(int i=1;i<=tot;++i)
        ci[ji[i]]=0;
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    shu=unique(t+1,t+n+1)-t-1;
    for(int i=1;i<=n;++i)
    a[i]=lower_bound(t+1,t+shu+1,a[i])-t;
    sz=sqrt(n);
    for(int i=1;i<=n;++i)
    {
        pos[i]=(i-1)/sz+1;
        if(!bl[pos[i]])
        bl[pos[i]]=i;
        br[pos[i]]=i;
    }   
    for(int i=1;i<=n;++i)
    ++cnt[a[i]][pos[i]];
    for(int i=1;i<=pos[n];++i)
    {
        for(int j=1;j<=shu;++j)
        cnt[j][i]+=cnt[j][i-1];
    }
    for(int i=1;i<=pos[n];++i)
    {
        memset(ji,0,sizeof(ji));
        cur=0;
        for(int j=i;j<=pos[n];++j)
        {
            for(int k=bl[j];k<=br[j];++k)
            {
                ++ji[a[k]];
                if(ji[a[k]]>ji[cur]||(ji[a[k]]==ji[cur]&&a[k]<cur))
                cur=a[k];
            }
            f[i][j]=cur;
        }
    }
    for(int i=1;i<=m;++i)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        l=(l+lastans-1)%n+1;
        r=(r+lastans-1)%n+1;
        if(r<l)
        swap(l,r);
        lastans=t[query(l,r)];
        printf("%d\n",lastans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/81207902
今日推荐