20210812C

19 篇文章 0 订阅

题解:
将数列分块一下,
变成sqrt ( n ) 块,每一块维护一个双端队列,以及建一个桶记录这一块中不同的数的个数。
对于操作①,我们暴力操作左右两边的块,
对于中间的块就是双端队列左边删一个,右边加一个,注意维护桶

对于操作②,暴力枚举左右两边的块,通过桶查询中间的块即可

时间复杂度:O ( n*sqrt ( n ) )

没怎么用过双端队列,所以维护的有点粗暴

代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#define N 100005

using namespace std;

int A[335][N], Belong[N], C[355], D[355], num, cnt, n, m;

void read(int &x)
{
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
	x = x * f;
}

deque <int> Q[N];
 
int main()
{
	freopen("queue.in", "r", stdin);
	freopen("queue.out", "w", stdout);
	read(n); read(m);
	num = sqrt(n);
	for (int i = 1; i <= n; i++) 
	{
		 int x; read(x); 
		 if (i  > num * cnt) ++cnt;
		 Q[cnt].push_back(x);
		 Belong[i] = cnt, ++A[cnt][x];
	}
	while (m--)
	{
		int opt; read(opt);
		if (opt == 1)
		 {
			int l, r; read(l); read(r);
			if (Belong[l] == Belong[r])
			{
				int G = Belong[l];
				l = l % num; if (l == 0) l = num;
				r = r % num; if (r == 0) r = num;
			    for (int i = 1; i < l; i++) 
				    C[i] = Q[G].front(), Q[G].pop_front();
			    for (int i = 1; i <= num - r; i++)
			        D[i] = Q[G].back(), Q[G].pop_back();
			        
			    int x = Q[G].back(); Q[G].pop_back(); Q[G].push_front(x); 
				for (int i = l - 1; i >= 1; i--) Q[G].push_front(C[i]);
			    for (int i = 1; i <= num - r; i++) Q[G].push_back(D[(num - r) - i + 1]);
			}
			else 
			{
				int G = Belong[l], k = l; while (Belong[k + 1] == G) ++k;
			    int len1 = k - l + 1;
			    for (int i = 1; i <= len1; i++)
				    C[len1 - i + 1] = Q[G].back(), Q[G].pop_back(), A[G][C[len1 - i + 1]]--; 
				    
			    int F = Belong[r], h = r; while (Belong[h - 1] == F) --h;
			    int len2 = r - h + 1; 
			    for (int i = 1; i <= len2; i++)
			        D[i] = Q[F].front(), Q[F].pop_front(), A[F][D[i]]--;
			    
			    Q[G].push_back(D[len2]), A[G][D[len2]]++;
			    for (int i = 1; i < len1; i++) Q[G].push_back(C[i]), A[G][C[i]]++;
	            
	            for (int i = len2 - 1; i >= 1; i--) Q[F].push_front(D[i]), A[F][D[i]]++; 
				int x = Q[F - 1].back(); if (F == G + 1) x = C[len1];
				Q[F].push_front(x), A[F][x]++;
	            
	            int last = C[len1];
	            for (int i = G + 1; i <= F - 1; i++)
	            {
				    Q[i].push_front(last); A[i][last]++;
					last = Q[i].back(); Q[i].pop_back();
					A[i][last]--; 	    
			    }
			}
		} 
		else 
		{
			int l, r, K, orz = 0; read(l); read(r); read(K);
			if (Belong[l] == Belong[r])
			{
				int G = Belong[l];
				l = l % num; if (l == 0) l = num;
				r = r % num; if (r == 0) r = num;
			    for (int i = 1; i < l; i++) 
				    C[i] = Q[G].front(), Q[G].pop_front();
			    for (int i = 1; i <= num - r; i++)
			        D[i] = Q[G].back(), Q[G].pop_back();
			        
				for (int i = l - 1; i >= 1; i--) 
				{
					if (C[i] == K) ++orz;
				    Q[G].push_front(C[i]);
				}
			    for (int i = 1; i <= num - r; i++) 
				{
				    if (D[(num - r) - i + 1] == K) ++orz;
					Q[G].push_back(D[(num - r) - i + 1]);
			    }
			    orz = A[G][K] - orz;
			}
			else 
			{
				int G = Belong[l], k = l; while (Belong[k + 1] == G) ++k;
			    int len1 = k - l + 1;
			    for (int i = 1; i <= len1; i++) C[len1 - i + 1] = Q[G].back(), Q[G].pop_back(); 
				for (int i = 1; i <= len1; i++) 
				{
				    if (C[i] == K) ++orz;
					Q[G].push_back(C[i]);
				}
				
			    int F = Belong[r], h = r; while (Belong[h - 1] == F) --h;
			    int len2 = r - h + 1; 
			    for (int i = 1; i <= len2; i++) D[i] = Q[F].front(), Q[F].pop_front();  
	            for (int i = len2; i >= 1; i--) 
				{
				    if (D[i] == K) ++orz;
					Q[F].push_front(D[i]); 
			    }
	            for (int i = G + 1; i <= F - 1; i++) orz += A[i][K];
			} 
			printf("%d\n", orz);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值