UVa12345 Dynamic len(set(a[L:R])) <带修莫队>

Dynamic len(set(a[L:R]))

In python, we can use len(start(a[L:R])) to calculate the number of distinct values of elements a[L],
a[L + 1], . . . , a[R ? 1].
Here are some interactive examples that may help you understand how it is done. Remember that
the indices of python lists start from 0.

a=[1,2,1,3,2,1,4]

print a[1:6]
[2, 1, 3, 2, 1]

print set(a[1:6])
set([1, 2, 3])

print
len(set(a[1:6]))
3

a[3]=2
print
len(set(a[1:6]))
2

print len(set(a[3:5]))
1
Your task is to simulate this process.

Input
There will be only one test case. The first line contains two integers n and m (1 ≤ n; m ≤ 50; 000).
The next line contains the original list.
All the integers are between 1 and 1,000,000 (inclusive). The next m lines contain the statements
that you need to execute.
A line formatted as ‘M x y’ (1 ≤ y ≤ 1; 000; 000) means \a[x] = y", and a line formatted as ‘Q x
y’ means \print len(set(a[x : y]))".
It is guaranteed that the statements will not cause \index out of range" error.
Output
Print the simulated result, one line for each query.

Sample Input
7 4
1 2 1 3 2 1 4
Q 1 6
M 3 2
Q 1 6
Q 3 5
Sample Output
3
2
1

标签:带修莫队

题目大意:给出一个长为n的序列,有m个操作,分为两类:1. $Q a b$ 询问此序列a~b位间有多少种不同数;2. $M a b$ 将第a位改为b。

本题数据范围只有五万,一看就是带根号的算法,可以$O(n\sqrt{n})$莫队水过。
我们发现Q操作是标准莫队,但M操作是修改,因而需用带修莫队。
带修莫队即在普通莫队的双指针种再加一个指针,指向时间。对于离线后询问建的扩展,如果是同一时间,就直接移动双指针;如果是不同时间,就先暴力移动时间指针,然后再移双指针即可。
暴力出奇迹~~~

附上AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAX_N 50000
#define MAX_C 1000000
using namespace std;
int n, m, tmp, col[MAX_N+5];
int cnt[MAX_C+5], pos[MAX_N+5], lst[MAX_N+5], ans[MAX_N+5];
bool mark[MAX_N+5];
struct Modify {int pos, x, pre;} M[MAX_N+5];
struct Query {int l, r, id, ts;} Q[MAX_N+5];
bool cmp(const Query &a, const Query &b) {
	return	pos[a.l] < pos[b.l] || 
			(pos[a.l] == pos[b.l] && pos[a.r] < pos[b.r]) || 
			(pos[a.l] == pos[b.l] && pos[a.r] == pos[b.r] && a.ts < b.ts);
}
void add(int x) {
	if (mark[x]) {
		cnt[col[x]]--;
		if (!cnt[col[x]])	tmp--;
	} else {
		if (!cnt[col[x]])	tmp++;
		cnt[col[x]]++;
	}
	mark[x] ^= 1;
}
void change(int x, int y) {
	if (mark[x])	add(x), col[x] = y, add(x);
	else	col[x] = y;
}
int main() {
	scanf("%d%d", &n, &m);
	int magic = (int)(sqrt((double)n+0.5));
	int tot = 0, ind = 0;
	for (int i = 1; i <= n; i++)	scanf("%d", &col[i]), lst[i] = col[i], pos[i] = i/magic;
	for (int i = 1; i <= m; i++) {
		char opt[2];
		int x, y;
		scanf("%s%d%d", opt, &x, &y);	x++;
		if (opt[0] == 'Q') {
			Q[++tot].id = tot;
			Q[tot].l = x, Q[tot].r = y, Q[tot].ts = ind;
		} else {
			M[++ind].pos = x, M[ind].x = y, M[ind].pre = lst[x];
			lst[x] = y;
		}
	}
	sort(Q+1, Q+tot+1, cmp);
	int now = 0, l = 1, r = 0;
	for (int i = 1; i <= tot; i++) {
		if (now < Q[i].ts)	for (int j = now+1; j <= Q[i].ts; j++)	change(M[j].pos, M[j].x);
		if (now > Q[i].ts)	for (int j = now; j > Q[i].ts; j--)	change(M[j].pos, M[j].pre);
		if (l > Q[i].l)	for (int j = l-1; j >= Q[i].l; j--)	add(j);
		if (r < Q[i].r)	for (int j = r+1; j <= Q[i].r; j++)	add(j);
		if (l < Q[i].l)	for (int j = l; j < Q[i].l; j++)	add(j);
		if (r > Q[i].r)	for (int j = r; j > Q[i].r; j--)	add(j);
		now = Q[i].ts, l = Q[i].l, r = Q[i].r;
		ans[Q[i].id] = tmp;
	}
	for (int i = 1; i <= tot; i++)	printf("%d\n", ans[i]);
	return 0;
}
posted @ 2017-09-25 17:05  Azrael_Death  阅读(241)  评论(0编辑  收藏  举报