题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=2724
Description
Input
修正一下
l = (l_ 0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1
Output
Sample Input
6 3
1 2 3 2 1 2
1 5
3 6
1 5
Sample Output
1
2
1
HINT
修正:n <= 40000, m <= 50000
题解:
显然,这道题要查询的是区间众数,感觉有点难搞,并不具有累加性(或者说不好处理累加性啊),怎么办呢,我们考虑分块进行暴力,有一点是显然的,我们可以在分块之后预处理出第i个块到第j个块的众数,这样我们在查询一个l到r的区间的众数的时候,就可以先提取出完全包含的块的众数,然后再暴力地处理两边的数据,具体方式是对两边的所有剩下的数进行一次l到r的出现次数统计,我们会发现,如果在l到r包含的完整块区间里不是最多的并且在两旁也没有出现过,那么他一定不是众数,所以我们的程序是先O(1)查询出l到r包含的完整区间的众数,然后再最多地暴力枚举2倍根号n个数即可,暴力求区间众数有一个很巧妙的地方就是我们可以顺序扫一遍然后存储每个数据出现的位置,然后在查询的时候可以直接查两个l和r出现在该数据结构(比如数组或者动态数组等)的那个位置(利用STL的lower _ bound和upper _ bound,当然也可以自己写二分),然后两个位置之差就是l到r所包含的数,这个思想非常巧妙。
(当然这道题如果不强制在线的话,还可以滚莫队233)
PS:分块真的是可以搞好多事情
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#define MAXN 50000+10
#define MINN 500+10
using namespace std;
map<int,int>m;
vector<int>v[MAXN];
int val[MAXN];
int len,n,mm;
int cnt[MINN][MINN];
int ccnt;
int rock[MAXN];
int a[MAXN],be[MAXN];
void pre(int zone){
memset(rock,0,sizeof(rock));
int maxn=0,loc=0;
for(register int i=(zone-1)*len+1;i<=n;i++){
rock[a[i]]++;
if(rock[a[i]]>maxn||(rock[a[i]]==maxn&&val[a[i]]<val[loc])){
loc=a[i];
maxn=rock[a[i]];
}
cnt[zone][be[i]]=loc;
}
}
int query(int from,int to,int x){
int temp=upper_bound(v[x].begin(),v[x].end(),to)-lower_bound(v[x].begin(),v[x].end(),from);
return temp;
}
int query(int from,int to){
int ans=cnt[be[from]+1][be[to]-1];
int maxn=query(from,to,ans);
for(register int i=from;i<=min(to,be[from]*len);i++){
int temp=query(from,to,a[i]);
if(temp>maxn||(temp==maxn&&val[a[i]]<val[ans])){
ans=a[i];
maxn=temp;
}
}
if(be[from]!=be[to]){
for(register int i=(be[to]-1)*len+1;i<=to;i++){
int temp=query(from,to,a[i]);
if(temp>maxn||(temp==maxn&&val[a[i]]<val[ans])){
ans=a[i];
maxn=temp;
}
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&mm);
len=sqrt(n);
int ans=0;
for(register int i=1;i<=n;i++) be[i]=(i-1)/len+1;
for(register int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(!m[a[i]]){
m[a[i]]=++ccnt;
val[ccnt]=a[i];//注意这里的离散化并不是需要排序,而只是给每一个数一个编号
}
a[i]=m[a[i]];//给数列的每个数一个编号
v[a[i]].push_back(i);//该编号的数的位置加入一个i
}
for(register int i=1;i<=be[n];i++) pre(i);//对每个块进行pre操作
for(register int i=1;i<=mm;i++){
int aa,bb;
scanf("%d%d",&aa,&bb);
aa=(aa+ans-1)%n+1;bb=(bb+ans-1)%n+1;
if(aa>bb)swap(aa,bb);
ans=val[query(aa,bb)];
printf("%d\n",ans);
}
return 0;
}
/*
20 3
1 0 25 14 34 1 25 25 48 8 4 4 9 8 2 2 3 3 3 10
1 20
10 16
4 8
*/