BZOJ2724 蒲公英 【分塊】
BZOJ2724 蒲公英
題目背景
親愛的哥哥:
你在那個城市裡面過得好嗎?
我在家裡面最近很開心呢。昨天晚上奶奶給我講了那個叫「絕望」的大壞蛋的故事的說!它把人們的房子和田地搞壞,還有好多小朋友也被它殺掉了。我覺得把那麼可怕的怪物召喚出來的那個壞蛋也很壞呢。不過奶奶說他是很難受的時候才做出這樣的事的……
最近村子裡長出了一大片一大片的蒲公英。一颳風,這些蒲公英就能飄到好遠的地方了呢。我覺得要是它們能飄到那個城市裡面,讓哥哥看看就好了呢!
哥哥你要快點回來哦!
愛你的妹妹 Violet
Azure 讀完這封信之後微笑了一下。
“蒲公英嗎……”
題目描述
在鄉下的小路旁種著許多蒲公英,而我們的問題正是與這些蒲公英有關。
為了簡化起見,我們把所有的蒲公英看成一個長度為n的序列
而每次詢問一個區間 [l,r],你需要回答區間裡出現次數最多的是哪種蒲公英,如果有若干種蒲公英出現次數相同,則輸出種類編號最小的那個。
注意,你的演算法必須是線上的
輸入輸出格式
輸入格式:
第一行兩個整數 n,m ,表示有n株蒲公英,m 次詢問。
接下來一行n個空格分隔的整數 ,表示蒲公英的種類
再接下來m 行每行兩個整數 ,我們令上次詢問的結果為 x(如果這是第一次詢問, 則 x=0)。
令 ,如果 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% 的資料,保證 。
對於 100% 的資料,保證
區間求眾數
分塊
表示第i到第j個塊中的眾數
先離散,然後預處理和,對於查詢,先把答案設定為完整塊的眾數,不是完整塊的部分就暴力列舉進行比較好了
時間&空間效率
#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;
}