https://www.luogu.com.cn/problem/P4168
1.预处理所有块端点[L,R]之间的众数和每个颜色出现的次数$cnt_{L,R}$。时间复杂度$O(NT^2)$,空间复杂度$O(NT^2)$。这样我们查询任意完整块区间的众数和其出现的次数都是$O(1)$。
2.对于询问操作$[l,r]$,暴力查询$[l,L)$、$(R,r]$区间颜色的出现次数,直接累加在$cnt[L,R]$上,然后每次加的时候比较该颜色是否会成为众数。最后遍历$[l,L)$、$(R,r]$,复原cnt数组。查询一次时间复杂度为块长度$O(N/T)$。
总时间复杂度$O(NT^2 + MN/T)$,空间复杂度$O(NT^2)$。 均值不等式得$T=N^{1/3}$
ps.对颜色先离散化,且要求保序。
3.注意到$cnt_{L,R}$的作用非常鸡肋,根本上我们只需要知道$[L,R]$之间的众数是什么,以及$[l,L)$、$(R,r]$出现的颜色在$[l,r]$之间出现的次数。这可以用二分解决。记录每个颜色出现的位置下标,然后二分l,r出现的位置,即可得出在$[l,r]$之间出现的次数。
时间复杂度:$O(NT+MN/T*logN)$
卡麻了,TLE了。如果查询改成后缀和的话就好了。实在懒得改了
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
int n,m;
int num;
const int N = 40010;
int st[N],ed[N],siz[N],belong[N],a[N];
int lsh[N];
vector<int> g[N];
int d[1010][1010];
void init_block(){
for(int i=1;i<=num;i++){
st[i] = n/num*(i-1)+1,ed[i] = n/num*i;
}
ed[num] = n;
for(int i=1;i<=num;i++){
for(int j = st[i];j<=ed[i];j++)
belong[j] = i;
siz[i] = ed[i] - st[i] + 1;
}
}
void pre(int x){
vector<int> cnt(n+1,0);
int mx = -1,ans = 0;
for(int i=st[x];i<=n;i++){
cnt[a[i]]++;
if(cnt[a[i]]>mx||(cnt[a[i]]==mx&&a[i]<ans)){
ans = a[i],mx = cnt[a[i]];
}
d[x][belong[i]] = ans;
}
}
int Count(int l,int r,int val){
int t = upper_bound(g[val].begin(), g[val].end(), r)- lower_bound(g[val].begin(), g[val].end(), l);
return t;
}
int query(int l,int r){
int x =belong[l],y = belong[r];
if(x==y){
int mx = 0,ans = 0;
for(int i=l;i<=r;i++){
int v =Count(l,r,a[i]);
if(v>mx||(v==mx)&&a[i]<ans){
ans = a[i],mx = v;
}
}
return ans ;
}
int ans =d[x+1][y-1];
int mx = Count(l,r,ans);
for(int i=l;i<=ed[x];i++){
int v =Count(l,r,a[i]);
if(v>mx||(v==mx)&&a[i]<ans){
ans = a[i],mx = v;
}
}
for(int i=r;i>=st[y];i--){
int v =Count(l,r,a[i]);
if(v>mx||(v==mx)&&a[i]<ans){
ans = a[i],mx = v;
}
}
return ans ;
}
int main(){
//delete when submit!!!!!!
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
cin>>n>>m;
num = max(1,(int)(n/sqrt(m*log2(n)))); init_block();
for(int i=1;i<=n;i++){
cin>>a[i]; lsh[i] = a[i];
}
sort(lsh+1,lsh+n+1);
int N= unique(lsh+1,lsh+n+1) - lsh-1;
for(int i=1;i<=n;i++){
a[i] = lower_bound(lsh+1,lsh+N+1,a[i])-lsh;
g[a[i]].push_back(i);
}
for(int i=1;i<=num;i++)
pre(i);
int ans =0;
while(m--){
int l,r;
cin>>l>>r;
l = (l+ans-1)%n+1;
r = (r+ans-1)%n+1;
if(l>r) swap(l,r);
ans = lsh[query(l,r)];
cout<<ans<<endl;
}
return 0;
}