【ybt金牌导航6-4-2】【luogu P1903】数颜色 / 维护队列(带修莫队)

数颜色 / 维护队列

题目链接:ybt金牌导航6-4-2 / luogu P1903

题目大意

要你维护一个序列,可能会改变一个位置的数,还有询问一个区间内有多少种数。

思路

这道题有多种做法,然后我们考虑用带修莫队来做。

莫队是两个指针第一个按块搞,第二个就按个搞。
那我们带修的话我们就可以加上一个时间指针。

那也是一个道理,我们就也是分成块,然后第一个排序按左边的块排,第二个排序按右边的块排,接着就按着时间排。
然后就每次三个指针移动一下就可以了。

然后至于时间指针的移动,把位置 \(x\)\(a\) 换成 \(b\),就相当于把 \(a\) 的贡献消除,加上 \(b\) 的贡献。

然后就差不多了,我们最优会选取 \(n^{\frac{2}{3}}\) 的长度,这样复杂度是 \(n^{\frac{5}{3}}\) 的。、
(搞这个长度直接用 \(\text{pow}\) 函数)

代码

#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

struct node {
	int t, x, y, num, ans;
}a[140001];
int n, m, x, y, block[140001], t, col[140001];
int fr[140001], to[140001], lst[140001], sz;
int q, tim, pl[140001], num[1000001], ans;
bool in[140001];
char op;

bool cmp(node x, node y) {//莫队的排序
	if (block[x.x] != block[y.x]) return block[x.x] < block[y.x];
	if (block[x.y] != block[y.y]) return block[x.y] < block[y.y];
	return x.t < y.t;
}

void clac(int p) {//更新当前位置的值
	if (in[p]) {
		num[col[p]]--;
		if (!num[col[p]]) ans--;
	}
	else {
		num[col[p]]++;
		if (num[col[p]] == 1) ans++;
	}
	in[p] ^= 1;
}

void change(int p, int t) {//换数
	if (in[p]) {
		clac(p);
		col[p] = t;
		clac(p);
	}
	else col[p] = t;
}

bool cmp1(node x, node y) {
	return x.num < y.num;
}

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &lst[i]);
		col[i] = lst[i];
	}
	
	sz = pow(n, 2.0 / 3);
	for (int i = 1; i <= n; i++)
		block[i] = (i - 1) / sz + 1;
	
	for (int i = 1; i <= m; i++) {
		op = getchar();
		while (op != 'Q' && op != 'R') op = getchar();
		
		if (op == 'Q') {
			scanf("%d %d", &x, &y);
			a[++q] = (node){tim, x, y, i, 0};
		}
		else {
			scanf("%d %d", &x, &y);
			pl[++tim] = x;
			fr[tim] = lst[x];
			to[tim] = y;
			lst[x] = y;
		}
	}
	
	sort(a + 1, a + q + 1, cmp);
	t = 0; x = 1; y = 0;
	for (int i = 1; i <= q; i++) {
		while (t < a[i].t) t++, change(pl[t], to[t]);//三个指针分别移动
		while (t > a[i].t) change(pl[t], fr[t]), t--;
		while (x < a[i].x) clac(x), x++;
		while (x > a[i].x) x--, clac(x);
		while (y < a[i].y) y++, clac(y);
		while (y > a[i].y) clac(y), y--;
		a[i].ans = ans;
	}
	
	sort(a + 1, a + q + 1, cmp1);
	for (int i = 1; i <= q; i++) printf("%d\n", a[i].ans);
	
	return 0;
}
posted @ 2021-09-30 17:14  あおいSakura  阅读(28)  评论(0编辑  收藏  举报