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

题目链接

题解

树套树做法暂时不会,先坑着

带修改的莫队

在普通莫队基础上加一个时间量

修改时调整区间,同时调整时间

具体看代码

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register

using namespace std;

const int N = 2000010, M = 50010;

int n, m, C[N], belong[N];

struct qus {
	int l, r, id, tim;//tim记录在这次询问之前最近它的修改
	bool operator <(qus z) const {
		if (belong[l] == belong[z.l]) {
			if (belong[r] == belong[z.r])
				return tim < z.tim;
			return r < z.r;
		}
		return l < z.l;
	}
}q[M];
struct node {
	int pos, v;
}o[M];

//o记录修改操作,q记录询问
int cnt1, cnt2;

int tot[N], ans, a[M];

inline void del(int c) {if(!(--tot[c])) ans--;}//删掉
inline void add(int c) {if(++tot[c] == 1) ans++;}//添加
inline void change(int now, int k) {
	if (q[k].l <= o[now].pos && o[now].pos <= q[k].r)
		del(C[o[now].pos]), add(o[now].v);
	swap(C[o[now].pos], o[now].v);//这里是交换,因为后面撤销操作需要掉换回来
	return ;
}

inline int gi() {
	RG int x = 0; RG char c = getchar(); bool f = 0;
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') c = getchar(), f = 1;
	while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
	return f ? -x : x;
}

int main() {
	int n = gi(), m = gi(), siz = pow(n, 0.666666666666);//siz为块的大小
	for (RG int i = 1; i <= n; i++) C[i] = gi(), belong[i] = (i-1)/siz+1;
	char type;
	while (m--) {
		scanf("\n%c", &type);
		if (type == 'Q') {
			q[++cnt1].l = gi(); q[cnt1].r = gi(); q[cnt1].id = cnt1; q[cnt1].tim = cnt2;
		}
		else o[++cnt2].pos = gi(), o[cnt2].v = gi();		
	}
	sort(q+1, q+1+cnt1);
	int l = 1, r = 0, now = 0;
	for (int i = 1; i <= cnt1; i++) {
		while (l > q[i].l) add(C[--l]);
		while (l < q[i].l) del(C[l++]);
		while (r < q[i].r) add(C[++r]);
		while (r > q[i].r) del(C[r--]);
		while (now < q[i].tim) change(++now, i);
		while (now > q[i].tim) change(now--, i);
		a[q[i].id] = ans;
	}
	for (int i = 1; i <= cnt1; i++)
		printf("%d\n", a[i]);
	return 0;
}

posted @ 2018-12-18 11:20  zzy2005  阅读(110)  评论(0编辑  收藏  举报