JZOJ5924. 【NOIP2018模拟10.23】Queue

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/83312071

题意:

数据范围:

Analysis:

如果用二维数据结构强行去维护它,会很难做,不妨考虑分块。
发现每一次就是对于每一个块之间最后一个挪到第一个,最后一个和第一个单独考虑。
那么要维护相对位置,和 a i = k a_i=k 的个数,后面那个可以开个桶来做,前面的显然用链表来维护,这样就做完了。
复杂度: O ( n n ) O(n\sqrt{n})
记录另一个做法:考虑每一次挪位操作,我们当做往他们之前插入一个虚点,原来的点当做不存在但是不删除。然后把操作离线下来,用 s p l a y splay 把最终序列按照如上维护出来,并且记录下来每一次加点,删点(不存在的相当于赋为0)的信息。
我们现在区间固定了下来,那么问题转化为,每一次对于一个点权信息更改,询问某个区间数值等于 k k 的个数。复杂度: O ( ( m + n ) log n ) O((m+n)\log n)

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
# include<cmath>
# pragma GCC optimize(2)
using namespace std;
const int N = 1e5 + 5;
const int K = 8e2 + 5;
int L[K],R[K],h[K],t[K],pos[N];
int num[K][N],nx[N],las[N],a[N];
int n,m,tot,len;
inline int read()
{
	int x = 0; char ch = getchar();
	for (; ch < '0' || ch > '9' ; ch = getchar());
	for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
	return x;
}
inline void add(int p,int x,int v) { num[p][x] += v; }
int main()
{
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	n = read(),m = read(); if (n) len = sqrt(n * 5),tot = n / len + (n % len ? 1 : 0);
	for (int i = 1 ; i <= n ; ++i) a[i] = read();
	for (int i = 1 ; i <= tot ; ++i) L[i] = R[i - 1] + 1,R[i] = min(n,len * i);
	for (int i = 1 ; i <= tot ; ++i)
	{
		h[i] = L[i],t[i] = R[i]; add(i,a[L[i]],1),pos[L[i]] = i;
		for (int j = L[i] + 1 ; j <= R[i] ; ++j) las[j] = j - 1,nx[j - 1] = j,add(i,a[j],1),pos[j] = i;
	}
	while (m--)
	{
		int opt = read(),l = read(),r = read();
		if (opt == 1)
		{
			if (l == r) continue;
			if (pos[l] == pos[r])
			{
				int k = l - L[pos[l]],p = h[pos[l]],k1 = R[pos[l]] - r,p1 = t[pos[l]];
				while (k--) p = nx[p]; while (k1--) p1 = las[p1];
				if (p == h[pos[l]]) h[pos[l]] = p1;
				if (p1 == t[pos[l]]) t[pos[l]] = las[p1];
				las[nx[p1]] = las[p1],nx[las[p1]] = nx[p1];
				las[p1] = las[p],nx[las[p]] = p1,nx[p1] = p,las[p] = p1;
			}else
			{
				int now = t[pos[l]],k1 = R[pos[l]] - l,p1 = t[pos[l]];
				while (k1--) p1 = las[p1]; int z = las[p1],y = nx[p1]; t[pos[l]] = las[now],nx[las[now]] = 0;
				add(pos[l],a[now],-1);
				for (int i = pos[l] + 1 ; i < pos[r] ; ++i)
				{
					add(i,a[now],1),las[now] = 0;
					las[h[i]] = now,nx[now] = h[i],h[i] = now;
					now = t[i],nx[las[now]] = 0,t[i] = las[now]; add(i,a[now],-1);
				} las[now] = 0;
				int k = r - L[pos[r]],p = h[pos[r]];
				while (k--) p = nx[p];
				if (p == t[pos[r]]) t[pos[r]] = las[p] ? las[p] : now;
				if (p != h[pos[r]]) las[h[pos[r]]] = now,nx[now] = h[pos[r]];
				else nx[now] = nx[p],las[nx[p]] = now;
				if (p != h[pos[r]]) nx[las[p]] = nx[p],las[nx[p]] = las[p];
				h[pos[r]] = now,add(pos[r],a[now],1),add(pos[r],a[p],-1);
				nx[p] = p1,las[p1] = p,las[p] = z,nx[z] = p,add(pos[l],a[p],1);
				if (!y) t[pos[l]] = p,nx[p] = las[p1] = 0; if (!z) h[pos[l]] = p;
			}
		}else
		{
			int k = read(),ans = 0;
			if (pos[l] == pos[r])
			{
				int cnt = l - L[pos[l]],p = h[pos[l]];
				while (cnt--) p = nx[p]; cnt = r - l + 1;
				while (cnt--) ans += a[p] == k,p = nx[p];
			}else
			{
				int cnt = R[pos[l]] - l + 1,p = t[pos[l]];
				while (cnt--) ans += a[p] == k,p = las[p];
				cnt = r - L[pos[r]] + 1,p = h[pos[r]];
				while (cnt--) ans += a[p] == k,p = nx[p];
				for (int i = pos[l] + 1 ; i < pos[r] ; ++i) ans += num[i][k];
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/83312071
今日推荐