【BZOJ2120】【块状链表】数颜色
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
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
4
3
4
HINT
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
【分析】
好吧,正解应该是树套树,但是...分块可以做....
我的方法很暴力...改了暴力重建..居然还可以过。。
1 /* 2 宋代 3 辛弃疾 4 青玉案·元夕 5 东风夜放花千树。更吹落、星如雨。宝马雕车香满路。凤箫声动,玉壶光转,一夜鱼龙舞。 6 蛾儿雪柳黄金缕。笑语盈盈暗香去。众里寻他千百度。蓦然回首,那人却在,灯火阑珊处。 7 */ 8 #include <iostream> 9 #include <cstdio> 10 #include <algorithm> 11 #include <cstring> 12 #include <vector> 13 #include <utility> 14 #include <iomanip> 15 #include <string> 16 #include <cmath> 17 #include <queue> 18 #include <assert.h> 19 #include <map> 20 #include <ctime> 21 #include <cstdlib> 22 #include <stack> 23 #include <set> 24 #define LOCAL 25 const int INF = 100000000; 26 const int MAXN = 10000 + 10; 27 const int maxnode = 20000 * 2 + 200000 * 20; 28 const int MAXM= 1000000 + 10; 29 using namespace std; 30 int tot; 31 int n, q, block_size; 32 int data[MAXN]; 33 int belong[MAXN], block[MAXN]; 34 int t[MAXN],last[MAXM]; 35 36 37 //寻找第x块内有多少个比v要小的 38 int find(int x, int v){ 39 int l = (x - 1) * block_size + 1, r = min(x * block_size, n); 40 int first = l; 41 while (l <= r){ 42 int mid = (l + r) >> 1; 43 if (block[mid] < v) l = mid + 1; 44 else r = mid - 1; 45 } 46 return l - first; 47 } 48 int query(int l, int r){ 49 int ans = 0; 50 if (belong[l] == belong[r]){ 51 for (int i = l; i <= r; i++) if (t[i] < l) ans++; 52 }else { 53 for (int i = l; i <= block_size * belong[l]; i++) if (t[i] < l) ans++; 54 for (int i = block_size * (belong[r] - 1) + 1; i <= r; i++) if (t[i] < l) ans++; 55 } 56 for (int i = belong[l] + 1; i < belong[r]; i++) ans += find(i, l); 57 return ans; 58 } 59 //处理块 60 void build(int x){ 61 int l = (x - 1) * block_size + 1, r = min(x * block_size, n); 62 for (int i = l; i <= r; i++) block[i] = t[i]; 63 sort(block + l, block + r + 1);//对一个块的上一次出现的颜色进行排序 64 } 65 //将x的颜色改变为v 66 void change(int x, int v){ 67 for (int i = 1; i <= n; i++) last[data[i]] = 0;//暴力重构 68 data[x] = v; 69 for (int i = 1; i <= n; i++){ 70 int tmp = t[i]; 71 t[i] = last[data[i]]; 72 if (tmp != t[i]) build(belong[i]); 73 last[data[i]] = i; 74 } 75 } 76 77 void init(){ 78 scanf("%d%d", &n, &q); 79 for (int i = 1; i <= n; i++) scanf("%d", &data[i]); 80 block_size = (int)(sqrt(n * 1.0)); 81 //tot记录总共块的个数 82 tot = n / block_size; 83 if (n % block_size) tot++; 84 85 for (int i = 1; i <= n; i++){ 86 //链表式插入 87 t[i] = last[data[i]]; 88 last[data[i]] = i; 89 belong[i] = (i - 1) / block_size + 1; 90 } 91 for (int i = 1; i <= tot; i++){ build(i); 92 } 93 } 94 void work(){ 95 for (int i = 1; i <= q; i++){ 96 char str[10]; 97 scanf("%s", str); 98 if (str[0] == 'Q'){ 99 int l, r; 100 scanf("%d%d", &l, &r); 101 printf("%d\n", query(l, r)); 102 }else{ 103 int l, x; 104 scanf("%d%d", &l, &x); 105 change(l, x); 106 } 107 } 108 } 109 110 int main(){ 111 112 init(); 113 work(); 114 return 0; 115 }