BZOJ 2120: 数颜色

Posted You Siki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2120: 数颜色相关的知识,希望对你有一定的参考价值。

 

2120: 数颜色

Time Limit: 6 Sec  Memory Limit: 259 MB
Submit: 3623  Solved: 1396
[Submit][Status][Discuss]

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。


2016.3.2新加数据两组by Nano_Ape

 

Source

 
[Submit][Status][Discuss]

 

这真是一道好题,貌似有好多种不同的做法。有人用树套树过的,有人用整体二分过的,有人用带修莫队过的,还有像我一样的蒟蒻用常数优化暴力过的。

虽然2016有新加数据,然而依然卡不住暴力,23333。

RunID User Problem Result Memory Time Language Code_Length Submit_Time
1734100 YOUSIKI 2120 Accepted 34496 kb 2340 ms C++/Edit 1411 B 2016-12-11 12:45:43
 1 #include <bits/stdc++.h>
 2 
 3 const int siz = 10000000;
 4 
 5 char buf[siz], *bit = buf;
 6 
 7 inline int nextInt (void) {
 8     register int ret = 0;
 9     register int neg = 0;
10     
11     while (*bit < 0)
12         if (*bit++ == -)
13             neg ^= true;
14     
15     while (*bit >= 0)
16         ret = ret*10 + *bit++ - 0;
17         
18     return neg ? -ret : ret;
19 }
20 
21 inline char nextChar (void) {
22     while (*bit != Q && *bit != R)++bit;
23     return *bit ++;
24 }
25 
26 const int maxn = 2000000 + 5;
27 
28 int n, m;
29 int cases;
30 int total;
31 int answer;
32 int col[maxn];
33 int map[maxn];
34 int vis[maxn];
35 
36 signed main (void) {
37     fread (buf, 1, siz, stdin);
38     
39     n = nextInt ();
40     m = nextInt ();
41     
42     for (register int i = 1; i <= n; ++i) {
43         int color = nextInt ();
44         if (map[color] == 0)
45             map[color] = ++total;
46         col[i] = map[color];
47     }
48     
49     for (register int i = 1; i <= n; ++i) {
50         switch (nextChar ()) {
51             case R : {
52                 int a = nextInt ();
53                 int b = nextInt ();
54                 if (map[b] == 0)
55                     map[b] = ++total;
56                 col[a] = map[b];
57                 break;
58             }
59             case Q : {
60                 int a = nextInt ();
61                 int b = nextInt ();
62                 answer = 0, ++cases;
63                 for (register int j = a; j <= b; ++j)
64                     if (vis[col[j]] != cases)++answer, vis[col[j]] = cases;
65                 printf("%d\n", answer);
66             }
67         }
68     }
69 }

 

然而不太理解为啥离散化一下就有这么大的用处。

RunID User Problem Result Memory Time Language Code_Length Submit_Time
1734122 YOUSIKI 2120 Time_Limit_Exceed 26684 kb 7632 ms C++/Edit 1289 B 2016-12-11 13:00:40
 1 #include <bits/stdc++.h>
 2 
 3 const int siz = 10000000;
 4 
 5 char buf[siz], *bit = buf;
 6 
 7 inline int nextInt (void) {
 8     register int ret = 0;
 9     register int neg = 0;
10     
11     while (*bit < 0)
12         if (*bit++ == -)
13             neg ^= true;
14     
15     while (*bit >= 0)
16         ret = ret*10 + *bit++ - 0;
17         
18     return neg ? -ret : ret;
19 }
20 
21 inline char nextChar (void) {
22     while (*bit != Q && *bit != R)++bit;
23     return *bit ++;
24 }
25 
26 const int maxn = 2000000 + 5;
27 
28 int n, m;
29 int cases;
30 int answer;
31 int col[maxn];
32 int vis[maxn];
33 
34 signed main (void) {
35     fread (buf, 1, siz, stdin);
36     
37     n = nextInt ();
38     m = nextInt ();
39     
40     for (register int i = 1; i <= n; ++i)
41         col[i] = nextInt ();
42         
43     for (register int i = 1; i <= m; ++i) {
44         switch (nextChar ()) {
45             case R : {
46                 int a = nextInt ();
47                 int b = nextInt ();
48                 col[a] = b;
49                 break;
50             }
51             case Q : {
52                 int a = nextInt ();
53                 int b = nextInt ();
54                 answer = 0, ++cases;
55                 for (register int j = a; j <= b; ++j)
56                     if (vis[col[j]] != cases)++answer, vis[col[j]] = cases;
57                 printf ("%d\n", answer);
58             }
59         }
60     }
61 }

 

当然,小生来写这道题不是为了练习暴力的,是为了学习带修莫队的。

 

有别于普通的莫队,带修莫队多了一维对时间的要求,每个询问可以表示为[l,r,t],表示区间需要我们维护到区间[l,r]在时刻t的存在情况。方法是,对于l,r还按照普通莫队的对l分组方式分组,组内对r排序,转移的时候暴力调整时间即可。貌似为了达到最优秀的复杂度,分组时的大小需要调整一下,但这题显然没有那么苛刻啦,o(* ̄▽ ̄*)ブ

 

  1 #include <bits/stdc++.h>
  2 
  3 const int siz = 10000000;
  4 
  5 char buf[siz], *bit = buf;
  6 
  7 inline int nextInt (void) {
  8     register int ret = 0;
  9     register int neg = 0;
 10     
 11     while (*bit < 0)
 12         if (*bit++ == -)
 13             neg ^= true;
 14     
 15     while (*bit >= 0)
 16         ret = ret*10 + *bit++ - 0;
 17         
 18     return neg ? -ret : ret;
 19 }
 20 
 21 inline char nextChar (void) {
 22     while (*bit != Q && *bit != R)++bit;
 23     return *bit ++;
 24 }
 25 
 26 const int maxn = 200000 + 5;
 27 const int maxm = 2000000 + 5;
 28 
 29 int n, m;
 30 int l, r;
 31 int s, t;
 32 int answer;
 33 int col[maxn];
 34 int vis[maxm];
 35 
 36 struct query {
 37     int l, r, id, ans;
 38 }qry[maxn]; int q;
 39 
 40 struct change {
 41     int p, a, b, id;
 42 }chg[maxn]; int c;
 43 
 44 inline bool cmp_lr (const query &A, const query &B) {
 45     if (A.l / s != B.l / s)
 46         return A.l < B.l;
 47     else
 48         return A.r < B.r;
 49 }
 50 
 51 inline bool cmp_id (const query &A, const query &B) {
 52     return A.id < B.id;
 53 }
 54 
 55 inline void removeColor (int c) {
 56     if (--vis[c] == 0)--answer;
 57 }
 58 
 59 inline void insertColor (int c) {
 60     if (++vis[c] == 1)++answer;
 61 }
 62 
 63 inline void removeChange (change &c) {
 64     col[c.p] = c.a;
 65     if (c.p >= l && c.p <= r) {
 66         removeColor(c.b);
 67         insertColor(c.a);
 68     }
 69 }
 70 
 71 inline void insertChange (change &c) {
 72     col[c.p] = c.b;
 73     if (c.p >= l && c.p <= r) {
 74         removeColor(c.a);
 75         insertColor(c.b);
 76     }
 77 }
 78 
 79 inline void solve (query &q) {
 80     while (t > 0 && chg[t].id > q.id)
 81         removeChange (chg[t--]);
 82     while (t < c && chg[t + 1].id < q.id)
 83         insertChange (chg[++t]);
 84         
 85     
 86         
 87     while (l < q.l)removeColor (col[l++]);
 88     while (l > q.l)insertColor (col[--l]);
 89     while (r < q.r)insertColor (col[++r]);
 90     while (r > q.r)removeColor (col[r--]);
 91     
 92     q.ans = answer;
 93 }
 94 
 95 signed main (void) {
 96     fread (buf, 1, siz, stdin);
 97     
 98     n = nextInt ();
 99     m = nextInt ();
100     
101     for (register int i = 1; i <= n; ++i)
102         col[i] = nextInt ();
103         
104     for (register int i = 1; i <= m; ++i) {
105         switch (nextChar ()) {
106             case R : {
107                 chg[++c].id = i;
108                 chg[c].p = nextInt ();
109                 chg[c].b = nextInt ();
110                 chg[c].a = col[chg[c].p];
111                 col[chg[c].p] = chg[c].b;
112                 break;
113             }
114             case Q : {
115                 qry[++q].id = i;
116                 qry[q].l = nextInt ();
117                 qry[q].r = nextInt ();
118             }
119         }
120     }
121     
122     s = sqrt (n); t = c; answer = 0; l = 1; r = 0;
123     
124     std::sort (qry + 1, qry + 1 + q, cmp_lr);
125     
126     for (register int i = 1; i <= q; ++i)solve(qry[i]);
127     
128     std::sort (qry + 1, qry + 1 + q, cmp_id);
129     
130     for (register int i = 1; i <= q; ++i)
131         printf ("%d\n", qry[i].ans);
132 }

 

@Author: YouSiki

以上是关于BZOJ 2120: 数颜色的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 2120]数颜色(带修改莫队)

[BZOJ2120][BZOJ2453]数颜色

BZOJ2453维护队列&&BZOJ2120数颜色

BZOJ 2120: 数颜色

bzoj2120: 数颜色

bzoj 2120 数颜色