「在更」初涉莫队

莫队?美队?暴力美学的经典诠释(两个都是

莫队是什么

呃……似乎没有找到「小Z的袜子命题报告」那一篇论文。

g1n0st:https://zhuanlan.zhihu.com/p/25017840

xsamsara:https://blog.csdn.net/qq_41357771/article/details/80470795

普通莫队

莫队用于处理一类区间问题:已知$[l,r]$就能够快速得到$[l+1,r]$,$[l,r-1]$此类区间的信息。

这种问题有一种最基础的暴力:

1     for (int i=1; i<=m; i++)
2     {
3         while (lt < q[i].l) del(lt++);
4         while (lt > q[i].l) add(--lt);
5         while (rt < q[i].r) add(++rt);
6         while (rt > q[i].r) del(rt--);
7         q[i].ans = ans;
8     }

类似于毛毛虫的思路扩张。

但是如果遇到$[1,n]$,$[mid,mid]$,$[1,n]$……的查询显然就被浪费了很多时间。

那么我们很自然地想到离线处理,把询问按照第一关键字l,第二关键字r的顺序排序。

然而光光这样是不够的,比如说$[1,100]$,$[1,200]$,$[2,3]$,$[2,100]$……的数据就可以卡爆单纯的排序。

同样是暴力的思想,同出一门的分块此时可以助莫队一臂之力。

我们可以这样:当l处在同一块时,按照r排序,否则按照l排序。

复杂度基本可以保证在$O(n\sqrtn)$

带修改莫队

带修莫队其实就是莫队再加一维时间轴,换句话说就是把修改操作也按照莫队的思想处理。

把修改操作也按照莫队的思想处理

嗯,这就是我学会带修莫队后对它的概括。


莫队例题

「普通莫队」1878: [SDOI2009]HH的项链

Description

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。

Input

第一行:一个整数N,表示项链的长度。 
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 
第三行:一个整数M,表示HH询问的个数。 
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。

Output

M行,每行一个整数,依次表示询问对应的答案。


题目分析

正解是树状数组,不过可以作为莫队的板子题。

 1 #include<bits/stdc++.h>
 2 const int maxn = 50003;
 3 const int maxm = 200035;
 4 const int maxNum = 1000035;
 5 
 6 struct node
 7 {
 8     int l,r,x,ans,id;
 9 }q[maxm];
10 int a[maxn],hsh[maxNum],ans;
11 int n,m,size;
12 
13 bool cmp(node a, node b){return (a.l/size < b.l/size)||(a.l/size == b.l/size&&a.r < b.r);}
14 bool cmpid(node a, node b){return a.id < b.id;}
15 int read()
16 {
17     int num = 0;
18     char ch = getchar();
19     bool fl = 0;
20     for (; !isdigit(ch); ch = getchar())
21         if (ch=='-') fl = 1;
22     for (; isdigit(ch); ch = getchar())
23         num = (num<<1)+(num<<3)+ch-48;
24     if (fl) num = -num;
25     return num;
26 }
27 void add(int x){if (!(hsh[a[x]]++)) ans++;}
28 void del(int x){if (!(--hsh[a[x]])) ans--;}
29 int main()
30 {
31     n = read(), size = (int)sqrt(n);
32     for (int i=1; i<=n; i++) a[i] = read();
33     m = read();
34     for (int i=1; i<=m; i++)
35         q[i].l = read(), q[i].r = read(), q[i].id = i;
36     std::sort(q+1, q+m+1, cmp);
37     int lt = 1, rt = 0;
38     for (int i=1; i<=m; i++)
39     {
40         while (lt < q[i].l) del(lt++);
41         while (lt > q[i].l) add(--lt);
42         while (rt < q[i].r) add(++rt);
43         while (rt > q[i].r) del(rt--);
44         q[i].ans = ans;
45     }
46     std::sort(q+1, q+m+1, cmpid);
47     for (int i=1; i<=m; i++) printf("%d\n",q[i].ans);
48     return 0;
49 }

「带修莫队」2120: 数颜色

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支画笔中共有几种不同颜色的画笔。

HINT

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


题目分析

就是上面的分析,

直接挂代码吧

 1 #include<bits/stdc++.h>
 2 const int maxn = 50035;
 3 const int maxNum = 1000035;
 4 
 5 int size;
 6 struct CHANGEs
 7 {
 8     int x,y,lst;
 9     CHANGEs() {}
10     CHANGEs(int a, int b, int c):x(a),y(b),lst(c) {}
11 }u[maxn];
12 struct QRs
13 {
14     int l,r,tim,id;
15     bool operator < (QRs a) const
16     {
17         if (l/size==a.l/size){
18             if (r/size==a.r/size){
19                 return tim < a.tim;
20             }else return r/size < a.r/size;
21         }else return l/size < a.l/size;
22     }
23     QRs() {}
24     QRs(int a, int b, int c, int d):l(a),r(b),tim(c),id(d) {}
25 }q[maxn];
26 int n,m,cntu,cntq,L,R,now,tot;
27 int a[maxn],lst[maxn],ans[maxn],hsh[maxNum];
28 char ch[13];
29 
30 int read()
31 {
32     int num = 0;
33     char ch = getchar();
34     bool fl = 0;
35     for (; !isdigit(ch); ch = getchar())
36         if (ch=='-') fl = 1;
37     for (; isdigit(ch); ch = getchar())
38         num = (num<<1)+(num<<3)+ch-48;
39     if (fl) num = -num;
40     return num;
41 }
42 void change(int x, int col)
43 {
44     if (x >= L&&x <= R){
45         if (!(--hsh[a[x]])) tot--;
46         a[x] = col;
47         if (!(hsh[a[x]]++)) tot++;
48     }else a[x] = col;
49 }
50 void add(int x){if (!(hsh[x]++)) tot++;}
51 void del(int x){if (!(--hsh[x])) tot--;}
52 int main()
53 {
54     n = read(), m = read();
55     size = pow(n, 2.0/3);
56     for (int i=1; i<=n; i++) lst[i] = a[i] = read();
57     for (int i=1; i<=m; i++)
58     {
59         scanf("%s",ch);
60         int l = read(), r = read();
61         if (ch[0]=='Q')
62             q[++cntq] = QRs(l, r, cntu, cntq);
63         else{
64             u[++cntu] = CHANGEs(l, r, lst[l]);
65             lst[l] = r;
66         }
67     }
68     std::sort(q+1, q+cntq+1);
69     L = 1, R = 0, now = 0;
70     for (int i=1; i<=cntq; i++)
71     {
72         while (q[i].tim < now) change(u[now].x, u[now].lst),now--;
73         while (q[i].tim > now) now++,change(u[now].x, u[now].y);
74         while (L < q[i].l) del(a[L++]);
75         while (L > q[i].l) add(a[--L]);
76         while (R < q[i].r) add(a[++R]);
77         while (R > q[i].r) del(a[R--]);
78         ans[q[i].id] = tot;
79     }
80     for (int i=1; i<=cntq; i++) printf("%d\n",ans[i]);
81     return 0;
82 }

「在更」

猜你喜欢

转载自www.cnblogs.com/antiquality/p/9173775.html
今日推荐