BZOJ2120 数颜色Count
Description
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
Input
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
Output
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
Sample Input
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
4
4
3
4
HINT
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
DreifO_o很不爽因为......她只不过写了写弹飞绵羊的代码啊(题解不还是我写的)...;
总之今天需要第二篇题解来缓和一下气氛;
和她一样吧...也是一道分块可做题.
这道题的分块更优美,优雅的暴力hhh;
对于序列中的每一个数:维护之前与它颜色相同的最近的一个块的位置,放在pre数组中;
然后!现在对于每一次询问,实际上是求出该区间中所有pre值小于l的值的数量,暴力扫一遍明显太慢而且与分块无关了,
所以我们可以对整块二分,残块暴力!
详见代码:
1 //2120 数颜色 Count__From BZOJ
2 //Bucket Method & Binary Search
3 #include<iostream>
4 #include<cstdio>
5 #include<cmath>
6 #include<algorithm>
7 using namespace std;
8
9 inline void Read(int&);
10 const int maxn = 10000 + 5;
11 int n, m, q, num;
12 int arr[maxn], pre[maxn];
13 int blo[maxn], temp[maxn]/*用来二分的数组*/;
14 int last[1000000 + 5];
15 void Update(int);
16 int Binary(int, int);
17
18 int main()
19 {
20 Read(n), Read(q);
21 m = sqrt(n), num = (n - 1) / m + 1;
22 for (int i = 1; i <= n; i++) {
23 blo[i] = (i - 1) / m + 1;
24 Read(arr[i]);
25 pre[i] = last[arr[i]];//维护pre
26 last[arr[i]] = i;
27 }
28 for (int i = 1; i <= num; i++) Update(i);//处理一下temp;
29 char ord;
30 int l, r;
31 while (q--) {
32 scanf("%s", &ord);
33 Read(l), Read(r);
34 if (ord == 'Q') {
35 int ans = 0, end = min(r, blo[l] * m);
36 for (int i = l; i <= end; i++)
37 if (pre[i] < l) ans++;
38 end = (blo[r] - 1)*m + 1;
39 if (blo[l] != blo[r])
40 for (int i = r; i >= end; i--)
41 if (pre[i] < l) ans++;
42 end = blo[r] - 1;
43 for (int i = blo[l] + 1; i <= end; i++)
44 ans += Binary(i, l);//二分查找
45 printf("%d\n", ans);
46 }
47 else {//暴力的修改
48 for (int i = 1; i <= n; i++) last[arr[i]] = 0;
49 arr[l] = r;
50 for (int i = 1; i <= n; i++) {
51 int tmp = pre[i];
52 pre[i] = last[arr[i]];
53 if (tmp != pre[i]) Update(blo[i]);
54 last[arr[i]] = i;
55 }
56 }
57 }
58 return 0;
59 }
60
61 int Binary(int k, int ans)
62 {
63 int l = (k - 1)*m + 1, r = k*m;
64 while (l <= r) {
65 int mid = l + r >> 1;
66 if (temp[mid] < ans) l = mid + 1;
67 else r = mid - 1;
68 }
69 return l - (k - 1)*m - 1;
70 }
71
72 void Update(int k)
73 {
74 int l = (k - 1)*m + 1, r = min(k*m, n);
75 for (int i = l; i <= r; i++)
76 temp[i] = pre[i];
77 sort(temp + l, temp + r + 1);//二分要求数组有序
78 }
79
80 inline void Read(int &x)
81 {
82 x = 0;
83 bool f = 0;
84 char c = getchar();
85 while (c < '0' || c > '9') {
86 f = (c == '-');
87 c = getchar();
88 }
89 while (c >= '0'&&c <= '9') {
90 x = x * 10 + c - '0';
91 c = getchar();
92 }
93 if (f) x = -x;
94 }