Description
给定 $n$ 个数,$m$ 次操作,操作分两种:
Q L R
:询问区间 $[L,R]$ 中有多少个不同的数;
R P Col
:把第 $P$ 个数替换为 $Col$ 。
$(1 \leq n,m \leq 5 \times 10^4$,数的大小均大于等于 $1$ 且不超过 $10^6)$
Source
Solution
看到这道题的询问,就很容易想到 莫队 。可是还有修改操作,普通的莫队不支持,怎么办呢?带修莫队 应运而生。
带修莫队,字面意思即是带修改的莫队。它与普通莫队不同的是,多了一个 时间戳,用来记录到当前这个询问时已经进行了多少次修改操作。
我们把询问和修改分别存下来。对于每一个询问,我们不仅要做到左右端点与当前询问一致,还要使修改次数与当前询问相同。如果我们修改得过多,那么应该删去多余的修改,修改过少则反之。
普通莫队写法:
1 | for (; l > ql; add(col[--l])); |
带修莫队新增的两句话:
1 | for (; t < qt; upd(++t, i)); |
其中 $qt$ 表示这个询问已修改的次数,$t$ 表示当前已修改的次数,$i$ 表示排序后是第 $i$ 个询问。
upd 操作:
1 | inline void upd(int x, int i) {//在第 i 个询问进行第 x 次修改 |
至于排序,和普通莫队大致相同。
普通排序:
1 | if (x.l / blockSize != y.l / blockSize) return x.l < y.l; |
若左端点不在同一块,则按左端点排序;若左端点在同一块,右端点不在同一块,则按右端点排序;若都在同一块,则按修改次数排序。
奇偶性排序:
1 | if (x.l / blockSize != y.l / blockSize) return x.l < y.l; |
若左端点在同一块,右端点不在同一块,则根据左端点所在块编号的奇偶性对右端点排序。其它与普通排序相同。
在带修莫队中,块的大小($blockSize$)设 $n^{\frac{2}{3}}$ 比较快。此时的时间复杂度约为 $O(n^{\frac{5}{3}})$,证明有些麻烦,这里暂不给出。
Code
1 |
|