P1903 [国家集训队]数颜色 / 维护队列(带修莫队)

题目

题目传送门
在这里插入图片描述

题解

  • 根据题意,我们有一些修改操作,所以这是一个带修莫队(废话)
  • 那么再给出的每个操作中,修改和询问是有顺序的,所以我们在排序是需要在加上一个时间的排序,来达到优化。
  • 当我们在查询时可再填加一个时间指针来表示到目前为止已经进行了几次修改,如果修改的次数大于当前要修改的问题编号,则把它还原,否则更新即可。
  • 块的大小为 n 2 3 n^{\frac{2}{3}} n32(不会证明,记住即可)

code

#include <bits/stdc++.h> 
using namespace std; 
const int maxn = 5e4 + 100; 
const int maxm = 1e6 + 100; 

template <typename T> 
inline void read(T &s) {
	s = 0; 
	T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
	while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w; 
}

int n, m, csize, qsize, ans; 
int a[maxn], res[maxn], pos[maxn], cnt[maxm];  
struct change { int p, col; } c[maxn]; // 记录修改的数组
struct query { int l, r, t, id; } q[maxn]; // 记录查询的数组

inline bool cmp(query aa, query bb) { 
	return pos[aa.l] == pos[bb.l] ? (pos[aa.r] == pos[bb.r] ? aa.t < bb.t : aa.r < bb.r) : aa.l < bb.l;
}
inline void del(int x) { if (--cnt[x] == 0) --ans;  }
inline void add(int x) { if (++cnt[x] == 1) ++ans;  }

int main() {
//	freopen("1.in", "r", stdin); 
//	freopen("1.out", "w", stdout); 
	read(n), read(m); 
	int blo = pow(n, 0.666666); // n的2/3次方
	for (int i = 1; i <= n; ++i) {
		read(a[i]); 
		pos[i] = i / blo; 
	}
	char opt[10]; 
	for (int i = 1; i <= m; ++i) {
		scanf("%s", opt); 
		if (opt[0] == 'Q') {
			++qsize; 
			read(q[qsize].l), read(q[qsize].r); 
			q[qsize].t = csize; 
			q[qsize].id = qsize; 
		}
		else {
			++csize; 
			read(c[csize].p), read(c[csize].col); 
		}
	}
	sort(q + 1, q + qsize + 1, cmp); 
	int l = 1, r = 0, t = 0; 
	for (int i = 1; i <= qsize; ++i) {
		int ql = q[i].l, qr = q[i].r; 
		while (t < q[i].t) {
			++t;
			if (l <= c[t].p && r >= c[t].p) {
				del(a[c[t].p]); 
				add(c[t].col); 
			}
			swap(a[c[t].p], c[t].col); 
		}
		while (t > q[i].t) {
			if (l <= c[t].p && r >= c[t].p) {
				del(a[c[t].p]); 
				add(c[t].col); 
			}
			swap(a[c[t].p], c[t].col);
			--t;
		}
		while (l < ql) del(a[l++]); 
		while (l > ql) add(a[--l]); 
		while (r < qr) add(a[++r]); 
		while (r > qr) del(a[r--]); 
		res[q[i].id] = ans; 
	}
	for (int i = 1; i <= qsize; ++i) 
		printf("%d\n", res[i]); 
	return 0; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值