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 }

 

posted @ 2017-10-23 21:24  Dreif  阅读(157)  评论(0编辑  收藏  举报