zoukankan      html  css  js  c++  java
  • [bzoj] 2724 蒲公英 || 分块

    原题

    强制在线,求[l,r]内的众数


    是分块的模板题。

    分块:
    把序列分为(sqrt(n))块,预处理好每个块内的答案,询问时整块直接求解,非整块暴力求解。因为非整块的数不会超过(2sqrt(n))个,所以算法的时间复杂度为(O((n+m)sqrt(n)))

    本题分块后,预处理两个数组:
    f[i][j]:第i块到第j块的答案(从i的左端点到j的右端点)
    cnt[i][j]:从序列开始到第j块结束,i数出现了多少次

    每次将非整块的答案处理出来后,与cnt结合比较出答案即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 40010
    #define B 210
    #define inf 0x3f3f3f3f
    using namespace std;
    int n,m,num,s,l,r,ans,a[N],b[N],sum[N],idx;
    int bl[B],br[B],f[B][B],cnt[N][B];
    bool v[N];
    
    int read()
    {
        int ans=0,fu=1;
        char j=getchar();
        for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
        for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
        return ans*fu;
    }
    
    void init()//预处理cnt和f
    {
        int k,cur,mxv,t,h,c;
        for (int i=1;i<=s;i++)
        {
    	k=bl[i];cur=inf;mxv=-inf;
    	for (int j=k;j<n;j++)
    	    sum[a[j]]=0;
    	for (int j=i;j<=s;j++)
    	{
    	    t=br[j];
    	    while (k<=t)
    	    {
    		c=++sum[a[k]];
    		if (c>mxv) mxv=c,cur=a[k];
    		else if (c==mxv && a[k]<cur) cur=a[k];
    		++k;
    	    }
    	    f[i][j]=cur;
    	}
        }
        memset(sum,0,sizeof(sum));
        for (int i=1;i<=s;i++)
        {
    	for (int j=0;j<idx;j++) cnt[j][i]=cnt[j][i-1];
    	h=bl[i];
    	t=br[i];
    	while (h<=t) cnt[a[h]][i]=++sum[a[h]],++h;
        }
    }
    
    int query(int l,int r)
    {
        int mxv=-inf,ret=inf,c;
        if (r-l<2*s)//如果长度<2*s,直接暴力即可
        {
    	for (int i=l;i<=r;i++)
    	    if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
    	    else ++sum[a[i]];
    	for (int i=l;i<=r;i++)
    	    if (v[a[i]])
    	    {
    		if (sum[a[i]]>mxv) mxv=sum[a[i]],ret=a[i];
    		else if (sum[a[i]]==mxv && a[i]<ret) ret=a[i];
    		v[a[i]]=0;
    	    }
    	return b[ret];
        }
        int L=l/num+1,R=r/num+1,st,en;
        if (l==bl[L]) --L;
        if (r==br[R]) ++R;
        ret=f[L+1][R-1];//整块部分的众数
        mxv=cnt[ret][R-1]-cnt[ret][L];//处理出整块中众数的次数
        en=br[L];st=bl[R];
        for (int i=l;i<=en;i++)//暴力
    	if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
    	else ++sum[a[i]];
        for (int i=st;i<=r;i++)
    	if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
    	else ++sum[a[i]];
        for (int i=l;i<=en;i++)
    	if (v[a[i]])
    	{
    	    c=cnt[a[i]][R-1]-cnt[a[i]][L];
    	    c+=sum[a[i]];
    	    if (c>mxv) mxv=c,ret=a[i];
    	    else if (c==mxv && a[i]<ret) ret=a[i];
    	    v[a[i]]=0;
    	}
        for (int i=st;i<=r;i++)
           if (v[a[i]])
    	{
    	    c=cnt[a[i]][R-1]-cnt[a[i]][L];
    	    c+=sum[a[i]];
    	    if (c>mxv) mxv=c,ret=a[i];
    	    else if (c==mxv && a[i]<ret) ret=a[i];
    	    v[a[i]]=0;
    	}
        return b[ret];
    }
    
    int main()
    {
        n=read();
        m=read();
        for (int i=0;i<n;i++) a[i]=b[i]=read();
        sort(b,b+n);
        idx=unique(b,b+n)-b;
        for (int i=0;i<n;i++)
    	a[i]=lower_bound(b,b+idx,a[i])-b;//离散化
        num=sqrt(n);
        for (int i=0;i<n;i++)
    	if (i%num==0) br[s]=i-1,bl[++s]=i;//bl[i]表示第i块的左端点,br[i]表示第i块的右端点
        br[s]=n-1;
        bl[s+1]=br[s+1]=n;
        init();
        while (m--)
        {
    	l=read();r=read();
    	l=(l+ans-1)%n;
    	r=(r+ans-1)%n;
    	if (l>r) swap(l,r);
    	printf("%d
    ",ans=query(l,r));
        }
        return 0;
    }
    
  • 相关阅读:
    c++父类指针子类指针转化分析
    setbuf手册
    c++细节
    cf727e
    总结
    UVa 10192 Vacation (最长公共子序列)
    HUNNU 11313 最长公共子序列(LCS)
    HDU 2069 Coin Change (经典DP)
    UVa 674 Coin Change (经典DP)
    UVa 10131 Is Bigger Smarter? (LDS+数据结构排序)
  • 原文地址:https://www.cnblogs.com/mrha/p/8176190.html
Copyright © 2011-2022 走看看