zoukankan      html  css  js  c++  java
  • BZOJ2724:[Violet 6]蒲公英

    浅谈分块:https://www.cnblogs.com/AKMer/p/10369816.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=2724

    对于每次询问的答案,要么是中间整块的众数,要么是在两侧不完整的块出现过的数。

    根据这个性质,我们可以(O(nsqrt{n}))求出每个块的众数和(sum[i][j]),表示从第一块到第(i)块内(j)出现了多少次。

    然后再用区间(dp)(O(nsqrt{n}))的复杂度内求出(mx[i][j]),表示第(i)整块到第(j)整块的众数是多少。

    对于每次询问,出现在两侧不完整的块的数,我们可以暴力扫描两侧把它们出现的次数丢到一个桶里,在加上在整块里出现的次数。

    然后直接找次数最多的那个数就行了。

    注意相同比大小要比原大小而不是离散化之后的大小。

    时间复杂度:(O(nsqrt{n}+msqrt{n}))

    空间复杂度:(O(nsqrt{n}))

    代码如下:

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn=4e4+5;
    
    int n,m,cnt,block,top,lstans;
    int v[maxn],tmp[maxn],bel[maxn],tot[maxn];
    int L[205],R[205],stk[405],mx[205][205],sum[205][maxn];
    
    int read() {
        int x=0,f=1;char ch=getchar();
        for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
        for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    int query(int l,int r,int v) {return sum[r][v]-sum[l-1][v];}
    
    int main() {
        n=read(),m=read(),block=sqrt(n);
        for(int i=1;i<=n;i++) {
            tmp[i]=v[i]=read();
            bel[i]=(i-1)/block+1;
            if(bel[i]!=bel[i-1])
                R[bel[i-1]]=i-1,L[bel[i]]=i;
        }
        R[bel[n]]=n,sort(tmp+1,tmp+n+1);
        cnt=unique(tmp+1,tmp+n+1)-tmp-1;
        for(int i=1;i<=n;i++)
            v[i]=lower_bound(tmp+1,tmp+cnt+1,v[i])-tmp;
        for(int i=1;i<=bel[n];i++) {
            memcpy(sum[i],sum[i-1],sizeof(sum[i]));
            int num2=0;
            for(int j=L[i];j<=R[i];j++)
                sum[i][v[j]]++;
    		for(int j=L[i];j<=R[i];j++) {
                int num1=query(i,i,v[j]);
                if((num1>num2)||(num1==num2&&tmp[v[j]]<tmp[mx[i][i]]))
                    mx[i][i]=v[j],num2=num1;
    		}
        }
        for(int len=2;len<=bel[n];len++)
            for(int i=1;i+len-1<=bel[n];i++) {
                int j=i+len-1,res=mx[i][j-1],num2=query(i,j,res);
                for(int k=L[j];k<=R[j];k++) {
                    int num1=query(i,j,v[k]);
                    if((num1>num2)||(num1==num2&&tmp[v[k]]<tmp[res]))
                       res=v[k],num2=num1;
                }
                mx[i][j]=res;
            }
        while(m--) {
            int l=read(),r=read(),res=0,num2=0;
            l=(l+lstans-1)%n+1,r=(r+lstans-1)%n+1;
            if(r<l)swap(l,r);
            if(bel[l]==bel[r]) {
                for(int i=l;i<=r;i++)
                    if((++tot[v[i]])==1)stk[++top]=v[i];
            }
            else {
                for(int i=l;i<=R[bel[l]];i++)
                    if((++tot[v[i]])==1) {
                        stk[++top]=v[i];
                        tot[v[i]]+=query(bel[l]+1,bel[r]-1,v[i]);
                    }
                for(int i=L[bel[r]];i<=r;i++)
                    if((++tot[v[i]])==1) {
                        stk[++top]=v[i];
                        tot[v[i]]+=query(bel[l]+1,bel[r]-1,v[i]);
                    }
                int tmp=mx[bel[l]+1][bel[r]-1];
                if(!tot[tmp]) {
                    stk[++top]=tmp;
                    tot[tmp]=query(bel[l]+1,bel[r]-1,tmp);
                }
            }
            for(int i=1;i<=top;i++) {
                int num1=tot[stk[i]];
                if((num1>num2)||(num1==num2&&tmp[stk[i]]<tmp[res]))
                   res=stk[i],num2=num1;
            }
            while(top)tot[stk[top--]]=0;
            lstans=tmp[res];
            printf("%d
    ",lstans);
        }
        return 0;
    }
    
  • 相关阅读:
    实现图片加载从模糊到清晰显示的方法
    审批流程设计方案-介绍(一)
    SpringBoot+JPA实现DDD(一)
    RabbitMQ使用入门
    SpringBoot+JPA实现DDD(六)
    SpringBoot+JPA实现DDD(五)
    Spring Boot+JPA实现DDD(四)
    Spring Boot+JPA实现DDD(三)
    Spring Boot+JPA实现DDD(二)
    DDD入门之解决了什么问题(二)
  • 原文地址:https://www.cnblogs.com/AKMer/p/10373522.html
Copyright © 2011-2022 走看看