【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

 

你可能感兴趣的:(ZOJ)