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;
    }
    
  • 相关阅读:
    在WCF中使用Flag Enumerations
    WCF开发教程资源收集
    [转]WCF 4 安全性和 WIF 简介
    Asp.Net Web API 2 官网菜鸟学习系列导航[持续更新中]
    Asp.Net Web API 2第十八课——Working with Entity Relations in OData
    Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)
    Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
    Asp.Net Web API 2第十五课——Model Validation(模型验证)
    函数 生成器 生成器表达式
    函数的进阶
  • 原文地址:https://www.cnblogs.com/mrha/p/8176190.html
Copyright © 2011-2022 走看看