【Codeforces 455D】Serega and Fun | 分块、双端队列

题目链接:问题连接

题目大意:

给出一个长度为 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(msqrt(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
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/113101466
今日推荐