Luogu P1903 [国家集训队] 数颜色 / 维护队列

发布时间 2023-05-25 12:10:46作者: 觉清风

题目来源https://www.luogu.com.cn/problem/P1903

[国家集训队] 数颜色 / 维护队列

题目描述

墨墨购买了一套 \(N\) 支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

  1. \(Q\ L\ R\) 代表询问你从第 \(L\) 支画笔到第 \(R\) 支画笔中共有几种不同颜色的画笔。

  2. \(R\ P\ Col\) 把第 \(P\) 支画笔替换为颜色 \(Col\)

为了满足墨墨的要求,你知道你需要干什么了吗?

输入格式

\(1\) 行两个整数 \(N\)\(M\),分别代表初始画笔的数量以及墨墨会做的事情的个数。

\(2\)\(N\) 个整数,分别代表初始画笔排中第 \(i\) 支画笔的颜色。

\(3\) 行到第 \(2+M\) 行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出格式

对于每一个 Query 的询问,你需要在对应的行中给出一个数字,代表第 \(L\) 支画笔到第 \(R\) 支画笔中共有几种不同颜色的画笔。

样例 #1

样例输入 #1

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

样例输出 #1

4
4
3
4

提示

对于30%的数据,\(n,m \leq 10000\)

对于60%的数据,\(n,m \leq 50000\)

对于所有数据,\(n,m \leq 133333\)

所有的输入数据中出现的所有整数均大于等于 \(1\) 且不超过 \(10^6\)

本题可能轻微卡常数

来源:bzoj2120

本题数据为洛谷自造数据,使用 CYaRon 耗时5分钟完成数据制作。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;

int n, m, block, l = 1, r = 0, ans;
int a[52113140], cnt[52113140], out[5211314], pos[5211314];
int ask_num, add_num;
string str;

struct ASK {
	int lift, right, time, identity;
}ask[5211314]; 

struct ADD {
	int pos, num;
}add[5211314];

inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch - '0');
		ch = getchar();
	}
	return x * f;
}

inline bool cmp_pretreat(const ASK &a, const ASK &b) {
	if (pos[a.lift] != pos[b.lift]) return pos[a.lift] < pos[b.lift];
	if (pos[a.right] != pos[b.right]) return pos[a.right] < pos[b.right];
	return a.time < b.time;
} 

inline void Del(int position) {
	if (-- cnt[a[position]] == 0) ans --;
	return;
}

inline void Add(int position) {
	if (cnt[a[position]] ++ == 0) ans ++;
	return;
}

inline void Time(int update) {
	if (add[update].pos < l || add[update].pos > r) {
		swap(add[update].num, a[add[update].pos]);
	}
	else {
		Del(add[update].pos);
		swap(add[update].num, a[add[update].pos]);
		Add(add[update].pos);
	}
	return;
}

int main() {
	ask[0].time = 0;
	cin >> n >> m; 
	block = pow(n, 1.00*2/3);
	for (int i = 1; i <= n; ++ i) {
		a[i] = read();
		pos[i] = (i - 1) / block + 1;
	}
	for (int i = 1; i <= m; ++ i) {
		cin >> str;
		if (str == "Q") {
			ask_num ++;
			ask[ask_num].lift = read();
			ask[ask_num].right = read();
			ask[ask_num].time = add_num;
			ask[ask_num].identity = ask_num;
		}
		else {
			add_num ++;
			add[add_num].pos = read();
			add[add_num].num = read(); 
		}
	}
	stable_sort(ask + 1, ask + 1 + ask_num, cmp_pretreat); 
	for (int i = 1, t = 0; i <= ask_num; ++ i) {
		while (l < ask[i].lift)  Del(l ++);
		while (l > ask[i].lift)  Add(-- l);
		while (r < ask[i].right)  Add(++ r);
		while (r > ask[i].right)  Del(r --);
		while (ask[i].time > t) Time(++ t);
		while (ask[i].time < t) Time(t --);
		out[ask[i].identity] = ans;
	}
	for (int i = 1; i <= ask_num; ++ i) {
		printf("%d\n",out[i]);
	}
	return 0;
}