原题链接 https://darkbzoj.cc/problem/2724
大致题意:给一个长度为n的序列,进行m次询问,每次询问输出区间内出现次数最多的数,强制在线。
离散化加分块
对于离散化后的每个数都建立一个前缀和数组,并预处理。
对每次询问l,r,若在同一个块内直接暴力搜索求解,若在不同块内,就直接加上中间块的答案。
对于在两边的块,可以用二分求出现次数,但这题数据量较小,直接暴力莽也过了
下面是代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e4+10;
int a[N];
int b[N];
int vis[N];
map<int,int> mp;
int n,m,cnt;
int len,tot;
//int block[N];
int l[N],r[N];
int sum[205][N];
int no[N];
void init(){
sort(b+1,b+1+n);
cnt=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
}
len=sqrt(n);
tot=n/len;
for(int i=1;i<=tot;i++){
l[i]=r[i-1]+1;
r[i]=l[i]+len-1;
}
if(n%len){
tot++;
l[tot]=r[tot-1]+1;
r[tot]=n;
}
int Max=0,tem;
memset(vis,0,(cnt+2)*sizeof(int));
for(int i=1;i<=tot;i++){
Max=0;
for(int j=l[i];j<=r[i];j++){
vis[a[j]]++;
no[j]=i;
}
for(int j=1;j<=cnt;j++){
sum[i][j]=vis[j];
//if(sum[i][j]-sum[i-1][j]>Max){
// Max=j;
}
// }
// block[i]=Max;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
init();
int L,R,x,y;
int Max=0;
while(m--){
scanf("%d%d",&L,&R);
memset(vis,0,(cnt+2)*sizeof(int));
L=(L+b[Max]-1)%n+1;
R=(R+b[Max]-1)%n+1;
if(L>R){
swap(L,R);
}
x=no[L],y=no[R];
Max=0;
if(x==y){
memset(vis,0,(cnt+2)*sizeof(int));
for(int i=L;i<=R;i++){
vis[a[i]]++;
if(vis[a[i]]>vis[Max]||(vis[a[i]]==vis[Max]&&a[i]<Max)){
Max=a[i];
}
}
printf("%d\n",b[Max]);
continue;
}
for(int i=L;i<=r[x];i++){
vis[a[i]]++;
}
for(int i=l[y];i<=R;i++){
vis[a[i]]++;
}
for(int i=1;i<=cnt;i++){
vis[i]+=sum[y-1][i]-sum[x][i];
if(vis[i]>vis[Max]){
Max=i;
}
}
printf("%d\n",b[Max]);
}
}