zoukankan      html  css  js  c++  java
  • bzoj2724: [Violet 6]蒲公英(离散化+分块)

      我好弱啊。。这题调了2天QwQ

      题目大意:给定一个长度为n(n<=40000)的序列,m(m<=50000)次询问l~r之间出现次数最多的数。(区间众数)

      这题如果用主席树就可以不用处理一堆前缀和。。蓝鹅我不会~T_T~

      把序列n分成sqrt(n)块,先把所有数离散化,预处理出poi[i][j]表示第i块到第j块的众数(即出现次数最多的数)。

      询问有两种情况:

      第一种情况是l~r在某个块中,那么直接扫一遍求出众数,效率O(sqrt(n))。

      第二种情况是l~r在多个块中,l在x块,r在y块,那么我们可以把它分为三部分:①l~x块最后一个数②x+1块~y-1块③y块第一个数~r。

      因为我们求出了poi数组,所以我们可以知道第二部分的众数,显然我们只要统计一下第一部分、第三部分每个数出现的次数,将它们和第二部分的众数出现的次数进行比较,出现次数最多的数就是l~r的众数。

      而第一部分、第三部分数的个数不超过2*sqrtn(n)个,所以扫一遍第一部分、第三部分的数,效率O(sqrt(n)),问题就是怎么O(1)求出第一部分、第三部分的每个数在l~r出现的次数了。如果是O(1),那么可以想到的就是前缀和,于是我们再预处理出qzh[i][a]表示前i块中a出现的次数,qzh2[i][j][a]表示第i块前j个数中a出现的次数。那么设第一部分某个数为a,l在x块,r在y块,它在l~r中出现的次数就是:

      qzh[y-1][a]-qzh[x-1][a]-qzh2[x][(l-1)%sqrtn==0?sqrtn:(l-1)%sqrtn][a]

      +qzh2[x][(r-1)%sqrtn+1==sqrtn?0:(r-1)%sqrtn+1][a]

      【写的好丑哇QAAAAQ

      第三部分同理,然后和第二部分预处理出来的众数在l~r出现的次数(求法同理)比较找出最大的就行了。

      预处理O(nsqrt(n)),询问O(qsqrt(n)),总的时间复杂度O((n+q)sqrt(n))。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<map>
    using namespace std;
    map<int,int>M[301];
    struct zs{int num,pos;}b[40001];
    int n,m,l,r,cnt,ans,poi[301][301],a[40001],pos[40001],sum[40001],qzh[301][40001],qzh2[301][301][301],num[301],ppos[301][40001];
    bool v[40001];
    bool cmp(zs a,zs b){return a.num<b.num;}
    int main()
    {
        scanf("%d %d",&n,&m);
        int sqrtn=(int)ceil(sqrt(n));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i].num=a[i],b[i].pos=i;
        sort(b+1,b+1+n,cmp);
        for(int i=1;i<=n;i++)
        {
            if(b[i].num!=b[i-1].num)cnt++;
            pos[b[i].pos]=cnt;
        }
        for(int i=1;i<=sqrtn;i++)
        for(int j=1;j<=sqrtn;j++)
        {
            if((i-1)*sqrtn+j<=n)if(M[i].find(a[(i-1)*sqrtn+j])==M[i].end())
            M[i][a[(i-1)*sqrtn+j]]=++num[i];
            ppos[i][pos[(i-1)*sqrtn+j]]=M[i][a[(i-1)*sqrtn+j]];
        }
        for(int i=1;i<=n;i++)qzh[((i-1)/sqrtn)+1][pos[i]]++;
        for(int i=1;i<=n;i++)for(int j=2;j<=sqrtn;j++)qzh[j][i]+=qzh[j-1][i];
        for(int i=1;i<=sqrtn;i++)for(int j=1;j<=sqrtn;j++)if((i-1)*sqrtn+j<=n)qzh2[i][j][ppos[i][pos[(i-1)*sqrtn+j]]]++;
        for(int i=1;i<=sqrtn;i++)
        {
            for(int k=1;k<=sqrtn;k++)if((i-1)*sqrtn+k<=n)v[pos[(i-1)*sqrtn+k]]=0;
            for(int k=1;k<=sqrtn;k++)
            if((i-1)*sqrtn+k<=n)
            if(!v[pos[(i-1)*sqrtn+k]])
            {
                for(int j=2;j<=sqrtn;j++)
                if((i-1)*sqrtn+j<=n)qzh2[i][j][ppos[i][pos[(i-1)*sqrtn+k]]]+=qzh2[i][j-1][ppos[i][pos[(i-1)*sqrtn+k]]];
                v[pos[(i-1)*sqrtn+k]]=1;
            }
        }
        for(int i=1;i<=sqrtn;i++)
        {
            memset(sum,0,sizeof(sum));
            int max=0,maxi=0;
            for(int j=i;j<=sqrtn;j++)
            {
                for(int k=1;k<=sqrtn;k++)
                {
                    int x=(j-1)*sqrtn+k;
                    if(x>n)break;
                    if(++sum[pos[x]]>max||((sum[pos[x]]==max)&&(pos[x]<pos[maxi])))max=sum[pos[x]],maxi=x;
                }
                poi[i][j]=maxi;
            }
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&l,&r);
            l=(l+ans-1)%n+1;r=(r+ans-1)%n+1;if(r<l)swap(l,r);
            if((int)ceil(r/sqrtn)==(int)ceil(l/sqrtn))
            {
                int maxx=0,maxi=0;
                memset(sum,0,sizeof(sum));
                for(int j=l;j<=r;j++)
                if(++sum[pos[j]]>maxx||((sum[pos[j]]==maxx)&&(pos[j]<pos[maxi])))maxx=sum[pos[j]],maxi=j;
                ans=a[maxi];
                printf("%d
    ",a[maxi]);
            }else
            {
                int ll=-1,rr=0;
                for(int j=0;j<=sqrtn;j++)
                {
                    if(j*sqrtn+1>=l&&(ll==-1))ll=j*sqrtn;
                    if(j*sqrtn<=r)rr=j*sqrtn;
                }
                int y=poi[ll/sqrtn+1][rr/sqrtn];
                for(int j=l;j<=ll;j++)
                {
                    int lll=y;
                    int x=qzh[rr/sqrtn][pos[j]]-qzh[max(ll/sqrtn-1,0)][pos[j]]-qzh2[ll/sqrtn][(l-1)%sqrtn==0?sqrtn:(l-1)%sqrtn][ppos[ll/sqrtn][pos[j]]]+qzh2[rr/sqrtn+1][(r-1)%sqrtn+1==sqrtn?0:(r-1)%sqrtn+1][ppos[rr/sqrtn+1][pos[j]]];
                    y=qzh[rr/sqrtn][pos[lll]]-qzh[max(ll/sqrtn-1,0)][pos[lll]]-qzh2[ll/sqrtn][(l-1)%sqrtn==0?sqrtn:(l-1)%sqrtn][ppos[ll/sqrtn][pos[lll]]]+qzh2[rr/sqrtn+1][(r-1)%sqrtn+1==sqrtn?0:(r-1)%sqrtn+1][ppos[rr/sqrtn+1][pos[lll]]];
                    if(x>y||((x==y)&&pos[j]<pos[lll]))y=j;else y=lll;
                } 
                for(int j=rr+1;j<=r;j++)
                {
                    int lll=y;
                       int x=qzh[rr/sqrtn][pos[j]]-qzh[max(ll/sqrtn-1,0)][pos[j]]-qzh2[ll/sqrtn][(l-1)%sqrtn==0?sqrtn:(l-1)%sqrtn][ppos[ll/sqrtn][pos[j]]]+qzh2[rr/sqrtn+1][(r-1)%sqrtn+1==sqrtn?0:(r-1)%sqrtn+1][ppos[rr/sqrtn+1][pos[j]]];
                    y=qzh[rr/sqrtn][pos[lll]]-qzh[max(ll/sqrtn-1,0)][pos[lll]]-qzh2[ll/sqrtn][(l-1)%sqrtn==0?sqrtn:(l-1)%sqrtn][ppos[ll/sqrtn][pos[lll]]]+qzh2[rr/sqrtn+1][(r-1)%sqrtn+1==sqrtn?0:(r-1)%sqrtn+1][ppos[rr/sqrtn+1][pos[lll]]];
                    if(x>y||((x==y)&&pos[j]<pos[lll]))y=j;else y=lll;
                }
                printf("%d
    ",a[y]);ans=a[y];
            }
        }
    }
    View Code
  • 相关阅读:
    如何运行 PPAS上的pgpoolII
    Postmaster主循环的大致流程
    对ListenSocket 的研究(三)
    对ListenSocket 的研究(二)
    对ListenSocket 的研究(五)
    PostgreSQL的postmaser的fork的学习体会
    赛门铁克公告:解密Kneber恶意软件 狼人:
    微软免费杀毒软件MSE最新版本释出 狼人:
    Facebook出现邮件错发故障 隐私安全再受关注 狼人:
    McAfee和Brocade将联合开发网络安全解决方案 狼人:
  • 原文地址:https://www.cnblogs.com/Sakits/p/6391030.html
Copyright © 2011-2022 走看看