• BZOJ2724 蒲公英 【分块】


    BZOJ2724 蒲公英


    题目背景

    亲爱的哥哥:
    你在那个城市里面过得好吗?
    我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……
    最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!
    哥哥你要快点回来哦!
    爱你的妹妹 Violet
    Azure 读完这封信之后微笑了一下。
    “蒲公英吗……”

    题目描述

    在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
    为了简化起见,我们把所有的蒲公英看成一个长度为n的序列 (a1,a2..an)其中 ai为一个正整数,表示第i棵蒲公英的种类编号。
    而每次询问一个区间 [l,r],你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
    注意,你的算法必须是在线的

    输入输出格式

    输入格式:

    第一行两个整数 n,m ,表示有n株蒲公英,m 次询问。
    接下来一行n个空格分隔的整数 ai ,表示蒲公英的种类
    再接下来m 行每行两个整数 l0,r0 ,我们令上次询问的结果为 x(如果这是第一次询问, 则 x=0)。
    l=(l0+x1)modn+1,r=(r0+x1)modn+1 ,如果 l>r,则交换 l,r 。
    最终的询问区间为[l,r]。

    输出格式:

    输出m 行。每行一个整数,表示每次询问的结果。

    输入输出样例

    输入样例#1

    6 3
    1 2 3 2 1 2
    1 5
    3 6
    1 5

    输出样例#1:

    1
    2
    1
    说明
    对于 20% 的数据,保证 1n,m30001n,m3000
    对于 100% 的数据,保证 1n40000,1m50000,1ai109


    区间求众数

    分块

    cnt[i][j]表示第i个数在前j个块中的数量
    ans[i][j]表示第i到第j个块中的众数
    先离散,然后预处理cntans,对于查询,先把答案设定为完整块的众数,不是完整块的部分就暴力枚举进行比较好了

    时间&空间效率O(nsqrt(n))


    #include<bits/stdc++.h>
    using namespace std;
    #define N 210
    #define M 40010
    #define For(x,a,b) for(int x=a;x<=b;x++)
    map<int,int> mp;
    int n,m,tot=0,lastans=0;
    int a[M],b[M],pre[M],t[N]={0};
    int block[M],L[N],R[N];
    int cnt[M][N]={0},ans[N][N]={0};
    int calc(int id,int lb,int rb){
        return cnt[id][rb]-cnt[id][lb-1];
    }
    void init(){
        int siz=sqrt(n);
        For(i,1,n)block[i]=(i-1)/siz+1;
        int bsiz=block[n];
        For(i,1,bsiz)L[i]=R[i-1]+1,R[i]=min(n,i*siz);
        For(i,1,n)cnt[b[i]][block[i]]++;
        For(i,1,tot)For(j,1,bsiz)cnt[i][j]+=cnt[i][j-1];
        For(i,1,bsiz)
            For(j,i,bsiz){
                int tmp=ans[i][j-1];
                For(k,L[j],R[j]){
                    int t1=calc(b[k],i,j),t2=calc(tmp,i,j);
                    if((t1==t2&&pre[b[k]]<pre[tmp])||t1>t2)tmp=b[k];
                }
                ans[i][j]=tmp;
            }
    }
    bool check(int id,int tmp){
        if(t[id]>t[tmp])return 1;
        if(t[id]==t[tmp]&&pre[id]<pre[tmp])return 1;
        return 0;
    }
    int solve(int l,int r){
        int pl=block[n]+1,pr=0;
        For(i,1,block[n])if(L[i]>=l)pl=min(pl,i);
        For(i,1,block[n])if(R[i]<=r)pr=max(pr,i);
        if(pl>pr){ 
            int tmp=0;
            For(i,l,r)t[b[i]]=0;
            For(i,l,r)t[b[i]]++;
            For(i,l,r)if(check(b[i],tmp))tmp=b[i];
            return tmp;
        }
        int tmp=ans[pl][pr];
        t[tmp]=calc(tmp,pl,pr);
        For(i,l,L[pl]-1)t[b[i]]=calc(b[i],pl,pr);
        For(i,R[pr]+1,r)t[b[i]]=calc(b[i],pl,pr);
        For(i,l,L[pl]-1)t[b[i]]++;
        For(i,R[pr]+1,r)t[b[i]]++;
        For(i,l,L[pl]-1)if(check(b[i],tmp))tmp=b[i];
        For(i,R[pr]+1,r)if(check(b[i],tmp))tmp=b[i];
        return tmp;
    }
    int main(){
        scanf("%d%d",&n,&m);
        For(i,1,n){
            scanf("%d",&a[i]);
            if(!mp.count(a[i])){
                mp[a[i]]=++tot;
                pre[tot]=a[i];
            }
            b[i]=mp[a[i]];
        }
        init();
        For(i,1,m){
            int l,r;scanf("%d%d",&l,&r);
            l=(l+lastans-1)%n+1;
            r=(r+lastans-1)%n+1;
            if(l>r)swap(l,r);
            lastans=pre[solve(l,r)];
            printf("%d
    ",lastans);
        }
        return 0;
    }
  • 相关阅读:
    linux常用命令三
    linux常用命令二
    redis持久化
    Linux环境redis集群搭建
    Maven常用命令
    Maven生成项目站点
    maven中import scope依赖方式解决单继承问题的理解
    maven使用assembly打包tar.gz文件
    Apache CXFjar包目录(转)
    WebService学习笔记一
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676372.html
Copyright © 2020-2023  润新知