洛谷 P4168 [Violet]蒲公英
------
题意在线求区间众数,若有多个输出权值最小的那个;
离线可采用莫队,在线由于区间众数不满足区间可加性(或许我不知道,不会维护),所以采用分块方式来写;
------
对于数据范围首先离散化,对长度为 n 的数组分为 sqrt(n) 块,预处理出第 i 块到第 j 块的区间众数答案;
预处理出数组每一个不同值的位置,vector存储;
对于一个询问[l,r],若 l 所在的块和 r 所在的块距离 <= 1,则暴力求解 [l,r] 的答案;
否则可以将 [l,r] 划分为 [l,L),[L,R],(R,r] 三个块,其中 [L,R] 是指 [l,r] 之间所有的块;
可以发现ans要么是预处理出的 [L,R] 的答案,要么ans是在,[l,L),(R,r] 之中,对于这两个区间,遍历每个值,用刚才存位置的 vector 二分查找出现次数;
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ll long long
#define ULL unsigned long long
#define Pair pair<LL,LL>
#define ls rt<<1
#define rs rt<<1|1
#define Pi acos(-1.0)
#define eps 1e-6
#define DBINF 1e100
#define mod 998244353
#define MAXN 1e18
#define MS 40009
const int sqMS = sqrt(MS)+5;
int n,m;
int a[MS]; // 原数组
int b[MS],tb;
int c[MS]; // 离散化数组
int size,bknum; // 块大小,块数
int bkl[MS],bkr[MS]; // 第 i 块左右区间
int belong[MS]; // i 位置所属块号
vector<int > vc[MS]; // 存 c[i] 位置
int cnt[MS]; // 计数
int p[sqMS][sqMS]; // i 块 ~ j 块 的区间众数
void a_hash_c(){ // 离散化
sort(b+1,b+n+1);
tb = 1;
for(int i=2;i<=n;i++){
if(b[i] != b[i-1]) b[++tb] = b[i];
}
for(int i=1;i<=n;i++){
c[i] = lower_bound(b+1,b+tb+1,a[i]) - b;
}
}
void init_bk(){ // 预处理块
size = sqrt(n);
bknum = n/size;
for(int i=1;i<=bknum;i++){
bkl[i] = (i-1)*size+1;
bkr[i] = i*size;
}
if(bkr[bknum] < n){
bknum++;
bkl[bknum] = bkr[bknum-1]+1;
bkr[bknum] = n;
}
for(int i=1;i<=bknum;i++){
for(int j=bkl[i];j<=bkr[i];j++){
belong[j] = i;
}
}
}
void init_numpos(){ // 存每个数位置
for(int i=1;i<=n;i++){
vc[c[i]].push_back(i);
}
}
void init_p(){ // 预处理 i 块 ~ j 块 的区间众数
for(int i=1;i<=bknum;i++){
int ans = 0;
int cntans = 0;
memset(cnt,0,sizeof cnt);
for(int j=bkl[i];j<=n;j++){
cnt[c[j]]++;
if(cntans < cnt[c[j]] || (cntans == cnt[c[j]] && ans > c[j])){
ans = c[j];
cntans = cnt[c[j]];
}
p[i][belong[j]] = ans;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
b[i] = a[i];
}
a_hash_c();
init_bk();
init_numpos();
init_p();
int lastans = 0;
while(m--){
int l,r;
cin >> l >> r;
l = (l+lastans-1)%n+1;
r = (r+lastans-1)%n+1;
if(l > r) swap(l,r);
if(belong[r] - belong[l] <= 1){ // l,r之间没有完整块
int ans = 0;
int cntans = 0;
for(int i=l;i<=r;i++){
int lpos = lower_bound(vc[c[i]].begin(),vc[c[i]].end(),l) - vc[c[i]].begin();
int rpos = upper_bound(vc[c[i]].begin(),vc[c[i]].end(),r) - vc[c[i]].begin();
int cc = rpos - lpos;
if(cc > cntans || (cc == cntans && c[i] < ans)){
ans = c[i];
cntans = cc;
}
}
cout << b[ans] << "\n";
lastans = b[ans];
continue;
}
int L = belong[l]+1;
int R = belong[r]-1;
int ans = p[L][R]; // 初始化为 l,r 之间的块的区间众数
int lanspos = lower_bound(vc[ans].begin(),vc[ans].end(),l) - vc[ans].begin();
int ranspos = lower_bound(vc[ans].begin(),vc[ans].end(),r) - vc[ans].begin();
int cntans = ranspos - lanspos; // [l,r] 区间内 ans 出现次数
for(int i=l;i<=bkl[L]-1;i++){ // 暴力处理左边不完整块
int lpos = lower_bound(vc[c[i]].begin(),vc[c[i]].end(),l) - vc[c[i]].begin();
int rpos = upper_bound(vc[c[i]].begin(),vc[c[i]].end(),r) - vc[c[i]].begin();
int cc = rpos - lpos;
if(cc > cntans || (cc == cntans && c[i] < ans)){
ans = c[i];
cntans = cc;
}
}
for(int i=bkr[R]+1;i<=r;i++){ // 暴力处理右边不完整块
int lpos = lower_bound(vc[c[i]].begin(),vc[c[i]].end(),l) - vc[c[i]].begin();
int rpos = upper_bound(vc[c[i]].begin(),vc[c[i]].end(),r) - vc[c[i]].begin();
int cc = rpos - lpos;
if(cc > cntans || (cc == cntans && c[i] < ans)){
ans = c[i];
cntans = cc;
}
}
cout << b[ans] << "\n";
lastans = b[ans];
}
return 0;
}