题目链接:问题连接
题目大意:
给出一个长度为 N N N的序列,对这个序列进行下面两种操作:
- 1 , l , r : 1 ,l,r: 1,l,r:将区间 [ l , r ] [l,r] [l,r]内循环移动一位
- 2 , l , r , k : 2,l,r,k: 2,l,r,k:询问区间 [ l , r ] 内 [l,r]内 [l,r]内有多少个数字 k k k,强制在线。
题目思路:
考虑分块就好了,将序列分成 s q r t ( n ) sqrt(n) sqrt(n)块,每一块维护一个双向队列。
对于一个区间的修改操作:在中间的块就可以直接通过 O 1 O1 O1的操作完成,两边的块特判一下就好了。
对于一个区间的询问操作:维护根号个块的数字种类数,完整的块直接用这个计算,不完整的直接特判。
复杂度: O ( m ∗ s q r t ( n ) ∗ 2 ) O(m*sqrt(n)*2) O(m∗sqrt(n)∗2)
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e5+700;
const ll mod= 100003;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int c[350][maxn];
deque<int>q[350];
int L[maxn],R[maxn];
int b[maxn];
int num[maxn];
int block = 0;
int save[maxn];
void Modify(int l,int r){
if(l>r) swap(l,r);
int s = b[l],t = b[r];
int cnt = 0;
if(s == t){
while(!q[s].empty()) save[++cnt] = q[s].back(),q[s].pop_back();
l-= (s-1)*block,r-=(s-1)*block;
int temp = save[r];
for(int i=r;i>=l+1;i--) save[i] = save[i-1];
save[l] = temp;
for(int i=1;i<=cnt;i++) q[s].push_front(save[i]);
return;
}
///t>s
int last = q[s].front();
for(int i=s+1;i<=t-1;i++){
q[i].push_back(last);
c[i][last]++;
last = q[i].front();
q[i].pop_front();
c[i][last]--;
}
cnt = 0;
///t块单独
for(int i=(t-1)*block+1;i<=r;i++) c[t][q[t].back()]--,save[++cnt] = q[t].back(),q[t].pop_back();
for(int i=cnt-1;i>=1;i--)c[t][save[i]]++,q[t].push_back(save[i]);
q[t].push_back(last),c[t][last]++;
last = save[cnt];
cnt = 0;
///s块单独
for(int i=l;i<=R[s];i++) c[s][q[s].front()]--,save[++cnt] = q[s].front(),q[s].pop_front();
q[s].push_front(last),c[s][last]++;
for(int i=cnt;i>=2;i--) c[s][save[i]]++,q[s].push_front(save[i]);
}
ll Query(int k,int l,int r){
if(l>r) swap(l,r);
int s = b[l],t = b[r];
int cnt = 0;
int ans = 0;
if(s == t){
while(!q[s].empty()) save[++cnt] = q[s].back(),q[s].pop_back();
l-= (s-1)*block,r-=(s-1)*block;
for(int i=l;i<=r;i++) if(save[i] == k) ans++;
for(int i=1;i<=cnt;i++) q[s].push_front(save[i]);
return ans;
}
for(int i=s+1;i<=t-1;i++) ans += c[i][k];
cnt = 0;
///t块单独
for(int i=(t-1)*block+1;i<=r;i++) ans += ((q[t].back() == k)?1:0),save[++cnt] = q[t].back(),q[t].pop_back();
for(int i=cnt;i>=1;i--) q[t].push_back(save[i]);
cnt = 0;
///s块单独
for(int i=l;i<=R[s];i++) ans += ((q[s].front() == k)?1:0),save[++cnt] = q[s].front(),q[s].pop_front();
for(int i=cnt;i>=1;i--) q[s].push_front(save[i]);
return ans;
}
int main(){
/*q[1].push_front(2);
q[1].push_front(3);
q[1].push_back(1);
debug(q[1].back());*/
read(n);
block = sqrt(n);
for(int i=1;i<=n;i++) read(num[i]);
for(int i=1;i<=n;i++){
b[i] = (i-1)/block + 1;
c[b[i]][num[i]]++;
L[i] = (i%block == 1)?1:0;
R[b[i]] = min(b[i]*block*1ll,n);
q[b[i]].push_front(num[i]);
}
int lastans = 0;
read(m);
for(int i=1;i<=m;i++){
int op,x,y,z;
read(op);read(x);read(y);
x = (x+lastans-1)%n + 1;
y = (y+lastans-1)%n + 1;
if(op == 1) Modify(x,y);
else{
read(z);
z = (z+lastans-1)%n+1;
lastans = Query(z,x,y);
di(lastans);
}
}
return 0;
}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/