【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

Sample Output

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 }
View Code

 

posted @ 2015-03-17 14:52  TCtower  阅读(280)  评论(0编辑  收藏  举报