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\n",lastans);
    }
    return 0;
}
posted @ 2018-06-22 15:29  Dream_maker_yk  阅读(115)  评论(0编辑  收藏  举报