[CF455D] Serega and Fun 题解
不知道大家做没做过数列分块基础9题?
插入删除操作可以用链表,线段树等数据结构都不好维护,考虑分块。对于修改操作,暴力重构受影响块的链表,发现除首尾块外,其他块都可以看作是区间左移一位,所以加头删尾即可。
每个块开一个数组(绝对不能是 \((un\_)map\),不然你会和我一样死的很诡异),表示这个块这种颜色有几个,统计就是很裸的了。
时间复杂度 \(O(n\sqrt n)\)。
//分块,用unmap记录每个块的答案会死
//块内每个数用链表记录
//时间复杂度 O(nsqrt(n))
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5,M=505;
int n,q,a[N],ls[N],nx[N];
int kl,num,fst[M],emd[M];
int mp[M][N];
void mk(int x){
fst[x]=x*kl-kl+1;
emd[x]=min(n,x*kl);
mp[x][a[emd[x]]]++;
for(int i=fst[x];i<min(x*kl,n);i++)
ls[i+1]=i,nx[i]=i+1,mp[x][a[i]]++;
}void change(int l,int r){
int fs=(l-1)/kl+1;
int fn=l-fs*kl+kl;
int ed=(r-1)/kl+1;
int en=r-ed*kl+kl;
int x=fst[fs],y=fst[ed];
for(int i=1;i<fn;i++) x=nx[x];
for(int i=1;i<en;i++) y=nx[y];
if(fst[ed]==y) fst[ed]=nx[y];
if(emd[ed]==y) emd[ed]=ls[y];
ls[nx[y]]=ls[y];nx[ls[y]]=nx[y];
nx[ls[x]]=y;ls[y]=ls[x];ls[x]=y;nx[y]=x;
if(fst[fs]==x) fst[fs]=y;
if(fs==ed) return;
int z=emd[fs],w=fst[fs+1];
nx[ls[z]]=0;emd[fs]=ls[z];
nx[ls[z]]=0;ls[z]=0;
nx[z]=w;ls[w]=z;fst[fs+1]=z;
mp[fs][a[z]]--;mp[fs][a[y]]++;
mp[fs+1][a[z]]++;mp[ed][a[y]]--;
for(int i=fs+1;i<ed;i++){
x=emd[i];y=fst[i+1];
mp[i][a[x]]--;mp[i+1][a[x]]++;
nx[ls[x]]=0;emd[i]=ls[x];
nx[ls[x]]=0;ls[x]=0;
nx[x]=y;ls[y]=x;fst[i+1]=x;
}
}int ans(int l,int r,int c){
int re=0;
int fs=(l-1)/kl+1;
int fn=l-fs*kl+kl;
int ed=(r-1)/kl+1;
int en=r-ed*kl+kl;
int x=fst[fs],y=fst[ed];
for(int i=1;i<fn;i++) x=nx[x];
if(fs==ed){
for(int i=fn;i<=en;i++)
re+=(c==a[x]),x=nx[x];
return re;
}for(int i=fn;i<=kl;i++)
re+=(c==a[x]),x=nx[x];
for(int i=1;i<=en;i++)
re+=(c==a[y]),y=nx[y];
for(int i=fs+1;i<ed;i++) re+=mp[i][c];
return re;
}int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;kl=sqrt(n);
num=(n-1)/kl+1;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=num;i++) mk(i);
cin>>q;int lans=0;
while(q--){
int o,l,r,x;
cin>>o>>l>>r;
l=(l+lans-1)%n+1;
r=(r+lans-1)%n+1;
if(l>r) swap(l,r);
if(o==2){
cin>>x;
x=(x+lans-1)%n+1;
lans=ans(l,r,x);
cout<<lans<<"\n";
}else change(l,r);
}return 0;
}