题意:
解法:
序列分块,每块大小为sqrt(n).
令cnt[i][j]为第i块中数字j的个数,这个可以O(n)预处理.
查询比较简单,就是普通的分块查询,复杂度O(sq).
循环右移操作:
左右两边的块O(sq)暴力循环右移,
中间的块如果暴力右移肯定不行,
一个快速循环右移的技巧是用双端队列deque,将末尾位置取出,放到开头就行了.
每块操作是O(1)的,因此操作O(sq)块的复杂度是O(sq).
综上:
算法总复杂度O(n*sq).
code:
#include <bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
int belong[maxm],l[maxm],r[maxm];
int cnt[333][maxm];
int num,block;
deque<int>d[333];
int a[maxm];
int n,q;
void init(){
cin>>n;for(int i=1;i<=n;i++)cin>>a[i];
block=sqrt(n);
int num=n/block;if(n%block)num++;
for(int i=1;i<=num;i++)l[i]=r[i-1]+1,r[i]=r[i-1]+block;
r[num]=n;
for(int i=1;i<=n;i++)belong[i]=(i-1)/block+1;
for(int i=1;i<=n;i++)d[belong[i]].push_back(a[i]),cnt[belong[i]][a[i]]++;
}
void update(int ql,int qr){
if(belong[ql]==belong[qr]){
int x=belong[ql];int temp=d[x][qr-l[x]];
for(int i=qr-l[x];i>ql-l[x];i--)d[x][i]=d[x][i-1];
d[x][ql-l[x]]=temp;
}else{
int x=belong[qr];int temp=d[x][qr-l[x]];
x=belong[ql];int last=d[x].back();cnt[x][last]--;
for(int i=r[x]-l[x];i>ql-l[x];i--)d[x][i]=d[x][i-1];
d[x][ql-l[x]]=temp;cnt[x][temp]++;
for(int i=belong[ql]+1;i<belong[qr];i++){
d[i].push_front(last);cnt[i][last]++;
last=d[i].back();d[i].pop_back();cnt[i][last]--;
}
x=belong[qr];cnt[x][d[x][qr-l[x]]]--;
for(int i=qr-l[x];i>l[x]-l[x];i--)d[x][i]=d[x][i-1];
d[x][l[x]-l[x]]=last;cnt[x][last]++;
}
}
int ask(int ql,int qr,int k){
int ans=0;
if(belong[ql]==belong[qr]){
int x=belong[ql];
for(int i=ql-l[x];i<=qr-l[x];i++)if(d[x][i]==k)ans++;
}else{
int x=belong[ql];
for(int i=ql-l[x];i<=r[x]-l[x];i++)if(d[x][i]==k)ans++;
x=belong[qr];
for(int i=l[x]-l[x];i<=qr-l[x];i++)if(d[x][i]==k)ans++;
for(int i=belong[ql]+1;i<belong[qr];i++)ans+=cnt[i][k];
}
return ans;
}
inline void solve(){
init();
int ans=0;
cin>>q;while(q--){
int op,ql,qr;cin>>op>>ql>>qr;
ql=(ql+ans-1)%n+1,qr=(qr+ans-1)%n+1;
if(ql>qr)swap(ql,qr);
if(op==1){
update(ql,qr);
}else{
int k;cin>>k;k=(k+ans-1)%n+1;
ans=ask(ql,qr,k);
cout<<ans<<endl;
}
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}