腾飞计划寒假第六课——莫队 2025/2/7
Lovely_yhb
·
·
个人记录
莫队
P3245 [HNOI2016] 大数
后缀差分,查区间 $[l,r]$ 有多少个 $(i,j)$ 满足 $suf_r-suf_l=0$,类似小 z 的袜子,莫队板子。
特判 $2$ 和 $5$ 的情况,因为 $2$ 和 $5$ 是 $10$ 的因数,$2$ 就是对每个偶数求到左端点的距离,$5$ 就是对每个 $0$ 或 $5$ 的位置求,前缀和一下即可。
### [P3604 美好的每一天](https://www.luogu.com.cn/problem/P3604)
比较聪明。把字母转化一下。
$a\rarr2^0,b\rarr2^1,c\rarr2^2,\dots,z\rarr2^{25}$。
将区间的数异或起来,最终数字二进制位 $1$ 的个数小于等于 $1$,即异或和等于 $0,1,2,4,\dots,2^{25}$。
开一个桶存状态,莫队插入时枚举 $0,1,2,4,\dots,2^{25}$,看原来的数异或和异或插入的数等于哪个,统计答案。类似 [P4462](https://www.luogu.com.cn/problem/P4462),莫队维护区间异或等于 $x$ 的。
### 莫队区间众数(可离线)
用堆存储出现次数。
维护一个数据结构。
$O(1)$ 插入删除,$O(1)$ 修改,$O(\sqrt n)$ 查询最大值。
值域分块。
如果某个块 $1$ 的个数等于 $0$,找下一个块,否则在块内暴力找。
莫队增删时直接更改值域分块的值,查的时候上述方法查。
### [P4137 Rmq Problem / mex](https://www.luogu.com.cn/problem/P4137)
如果出现过就标记为 $1$,值域分块,从第一个块开始,如果 $1$ 的个数等于块的长度,就找下一个,否则块内找,套个莫队。
### [CF877F Ann and Books](https://www.luogu.com.cn/problem/CF877F)
这个题特别聪明。
把第二类标记成 $-1$,第一类标记成 $1$,求和等于 $k$ 就行了。
---
### 题
给定一个序列,每次给出 $k$ 个区间,求 $k$ 个区间的并有多少个不同的颜色。
$n,m,k\le10^5$,时限 $3s$。
bitset 合并,每个区间有一个 01 串(用 bitset 存),表示这个颜色有没有出现过。合并就是将 bitset 或起来。
莫队处理每个区间的 bitset。
循环利用空间,把询问分成前一半后一半,只用开一半的 bitset。
莫队会慢一点,但是只慢一点。
---
### [P4688 [Ynoi2016] 掉进兔子洞](https://www.luogu.com.cn/problem/P4688)
有点聪明
删掉三个区间中出现次数最少的那次的个数。
每次查询每个区间维护一个长度为 $n$ 的 bitset,原序列中有几个该数字,就占几位。(这个我不会语言描述,举个例子)
比如 `1 1 1 1 1 1 4 4 5 5 8 9 9`。
如果有区间中的 $1$ 从第一个位置开始往后放,有 4 就从 第 $7$ 个位置开始放,有 $5$ 就从第9个位置开始放。
这样就可以保证数字的位置是一致的,此时把 bitset 与起来就是共同出现的数字及个数。
这种题莫队的作用是搞出 bitset,查询时把 bitset 与起来就行了。
### [P3674 小清新人渣的本愿](https://www.luogu.com.cn/problem/P3674)
比较聪明
差的情况,开值域大小的 bitset,如果有这个值就是 $1$,将 bitset 左移(右移也一样)$x$ 位,与上原来的,如果 bitset 中有 $1$,就说明有。
和的情况只需要建一个负作差的就行了。
乘的情况:查询的数 $x$ 将它分解成两个数的乘积,查这两个数有没有就行,分解出来的数对数量小于 $\sqrt n$。
bitset 用莫队处理。
### [P6134 [JSOI2015] 最小表示](https://www.luogu.com.cn/problem/P6134)
拓扑排序过程中维护一个 bitset 表示能到的点。
发现如果 $x$ 能到 $y$,$x$ 能到 $z$,$z$ 能到 $y$,则 $x$ 到 $y$ 能删。
枚举每条边两端的点,bitset 与起来,如果有 $1$ 那么这条边可以删。
## 回滚莫队
维护具有可减性的信息时(如区间最大值),尽管我们可以快速扩展区间,但无法高效地缩短区间,考虑如何不删除地回答询问。这看似是不可能的,但即使是不可减的信息可可以快速撤销。
仍然维护两个指针 $l,r$,对于每个块,初始左指针l指向下一个块的开头,这样左指针不会影响当前的答案,并且可以记录历史答案,右指针 $r=l-1$ 表示当前区间为空,对于右端点,由于其有序,我们可以直接扩展。右端点扩展完毕后,再扩展左端点直到目标位置并记录答案。需要维护一个历史答案。
每次询问完撤销左端点对信息的影响,再进行下一个询问。
排序后右端点递增,只会往后扩展,不会删除,左端点可能会删除,记历史答案,查询时先将左端点置于当前查询的位置,再扩展右端点。
## 带修莫队
强行加上一维修改时间戳,然后排序方式按照左端点所在块、右端点所在块和时间来排。导致块内的修改时间都是单调递增的。
这类问题块的大小一般是 $B=n^{\frac{2}{3}}$。
### [P5906 【模板】回滚莫队&不删除莫队](https://www.luogu.com.cn/problem/P5906)
回滚莫队板子题。
先把询问离线,然后还是按照左端点所在的排序,块内右端点排序。
对于左端点再某个块内的所有查询,具体可以分为两种。
对原序列分个块,如果询问的左右端点再同一个块内,暴力查询。
根据之前的排序,保证了左端点为同一个块是右端点的单调递增,这时我们只需要让左端点进行回滚。暴力一点,每次把左端点赋成所在块的右边界,然后往左扫,单次扫是根号的,而且右端点是单调的,总体是 $O(n\sqrt n)$。
### [P1903 [国家集训队] 数颜色 / 维护队列](https://www.luogu.com.cn/problem/P1903)
带修莫队板子题
对于某个询问,用 $(l,r,t)$ 来表示。其中 $l$,$r$ 表示询问在序列上的区间,$t$ 表示当前询问的时间,即在此询问之前进行了多少次修改操作。
首先类似普通莫队,对询问排序,不同的是 $l$ 和 $r$ 都要按照块排序,然后再把 $t$ 从小到大排序。
这样普通莫队的操作就变成了三维莫队。我们每次询问前进行对于时间维度的修改操作即可。