【BZOJ 2120】数颜色

1.题目链接。也是一种区间元素种类数的询问,但是加了修改。

2.带修莫队时可以解决这种问题的,带修莫队就是带有修改的莫队算法,在原来算法的基础上加了一个时间戳,这个是干嘛的呢?其实就是判断一下当前的询问是不是完成了正确的修改,如果发现修改的次数少了或者多了,就改回来。排序的时候还是和普通的莫队类似,如果前边都相同就按照时间戳排序。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 50500
#define maxc 1001000
int a[maxn], cnt[maxc], ans[maxn], belong[maxn];
struct query {
	int l, r, time, id;
} q[maxn];
struct modify {
	int pos, color, last;
} c[maxn];
int cntq, cntc, n, m, S, bnum;
int cmp(query a, query b) {
	return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.time < b.time);
}
#define isdigit(x) ((x) >= '0' && (x) <= '9')
inline int read() {
	int res = 0;
	char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
	return res;
}
int main() {
	n = read(), m = read();
	S = pow(n, 2.0 / 3.0);
	bnum = ceil((double)n / S);
	for (int i = 1; i <= bnum; ++i)
		for (int j = (i - 1) * S + 1; j <= i * S; ++j) belong[j] = i;
	for (int i = 1; i <= n; ++i)
		a[i] = read();
	for (int i = 1; i <= m; ++i) {
		char opt[100];
		scanf("%s", opt);
		if (opt[0] == 'Q') 
		{
			q[++cntq].l = read();
			q[cntq].r = read();
			q[cntq].time = cntc;
			q[cntq].id = cntq;
		}
		else if (opt[0] == 'R') {
			c[++cntc].pos = read();
			c[cntc].color = read();
		}
	}
	sort(q + 1, q + cntq + 1, cmp);
	int l = 1, r = 0, time = 0, now = 0;
	for (int i = 1; i <= cntq; ++i) {
		int ql = q[i].l, qr = q[i].r, qt = q[i].time;
		while (l < ql) now -= !--cnt[a[l++]];
		while (l > ql) now += !cnt[a[--l]]++;
		while (r < qr) now += !cnt[a[++r]]++;
		while (r > qr) now -= !--cnt[a[r--]];
		while (time < qt) {
			++time;
			if (ql <= c[time].pos && c[time].pos <= qr) now -= !--cnt[a[c[time].pos]] - !cnt[c[time].color]++;
			swap(a[c[time].pos], c[time].color);
		}
		while (time > qt) {
			if (ql <= c[time].pos && c[time].pos <= qr) now -= !--cnt[a[c[time].pos]] - !cnt[c[time].color]++;
			swap(a[c[time].pos], c[time].color);
			--time;
		}
		ans[q[i].id] = now;
	}
	for (int i = 1; i <= cntq; ++i)
		printf("%d\n", ans[i]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值