BZOJ2120&&2453 数颜色&&维护队列

2453: 维护队列

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1442 Solved: 678
[Submit][Status][Discuss]

Description

你小时候玩过弹珠吗?
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。

Input

输入文件第一行包含两个整数N和M。
第二行N个整数,表示初始队列中弹珠的颜色。
接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。

Output

对于每个Q操作,输出一行表示询问结果。

Sample Input

2 3

1 2

Q 1 2

R 1 2

Q 1 2

Sample Output

2

1

HINT

对于100%的数据,有\(1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000\),小朋友A不会修改超过\(1000\)次,所有颜色均用\(1\)\(10^6\)的整数表示。

题解

待修改的莫队,对于每个询问,开三维\(l\),\(r\),\(t\),表示询问区间\([l,r]\),在第\(t\)次操作之后。先按\(l\)所在块排序,再按\(r\)所在块排序,再按\(t\)排序即可。
执行的时候,先把修改时间定位,然后定位右端点,最后定位左端点。分块大小\(n^\frac{2}{3}\),时间复杂度\(O(n^\frac{5}{3})\)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#include <string>
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void read(T &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9') c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    if(c == '-') x = -x;
}
inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a < b ? a : b;}
const int INF = 0x3f3f3f3f;
const int MAXN = 1000000 + 10;
int n,m,color[MAXN],p[MAXN],c[MAXN],last[MAXN],ctot,qtot,belong[MAXN],size;
char s[100];
struct Node
{
	int l, r, t, rank;
}node[MAXN];
bool cmp(Node a, Node b)
{
	return belong[a.l] == belong[b.l] ? (belong[a.r] == belong[b.r] ? a.t < b.t : belong[a.r] < belong[b.r]) : belong[a.l] < belong[b.l];
}
int l = 1, r = 0, now = 0, ans = 0, tong[MAXN], a[MAXN], pos[MAXN];
void add(int x){ans += (++ tong[x]) == 1;}
void del(int x){ans -= (-- tong[x]) == 0;}
void change(int p, int c)
{
	if(l <= p && p <= r) add(c), del(color[p]);
	color[p] = c;
}
int main()
{
	read(n), read(m);
	for(int i = 1;i <= n;++ i) read(color[i]), tong[i] = color[i];
	for(int i = 1;i <= m;++ i)
	{
		scanf("%s", s + 1);
		if(s[1] == 'Q') ++ qtot, read(node[qtot].l), read(node[qtot].r), node[qtot].t = ctot, node[qtot].rank = qtot;
		else if(s[1] == 'R') ++ ctot, read(p[ctot]), read(c[ctot]), last[ctot] = tong[p[ctot]], tong[p[ctot]] = c[ctot];
	}
	memset(tong, 0, sizeof(tong));
	int size = pow(n, 0.66667);
	for(int i = 1;i <= qtot;++ i)
		if((i - 1) % size == 0) pos[i] = pos[i - 1] + 1;
		else pos[i] = pos[i - 1];
	std::sort(node + 1, node + 1 + qtot, cmp);
	for(int i = 1;i <= qtot;++ i)
	{
		while(now < node[i].t) ++ now, change(p[now], c[now]);
		while(now > node[i].t) change(p[now], last[now]), -- now;
		while(r < node[i].r) ++ r, add(color[r]);
		while(r > node[i].r) del(color[r]), -- r;
		while(l < node[i].l) del(color[l]), ++ l;
		while(l > node[i].l) -- l, add(color[l]);
		a[node[i].rank] = ans;
	}
	for(int i = 1;i <= qtot;++ i) printf("%d\n", a[i]);
	return 0;
}
posted @ 2018-02-26 08:42  嘒彼小星  阅读(142)  评论(0编辑  收藏  举报