P1903 [国家集训队] 数颜色 / 维护队列 题解

发布时间 2023-12-19 11:48:51作者: Creeper_l

原题链接:P1903

题意

对于一个序列,维护两个操作:

  • \(a_{x}\) 改为 \(p\)

  • \(l\)\(r\) 中有多少个不同的数

思路

这道题本来是带修莫队的板子的,但是我是使用分块做的。

具体思路挺板的...但是这道题其实有个 \(trick\)。就是我们先预处理记录 \(pre_{i}\) 表示上一个 \(a_{i}\) 出现的位置。假设查询的区间为 \(l\)\(r\),如果 \(pre_{now} < l\),那么就说明当前这个颜色在这个区间内还没有出现过,于是 \(ans++\)。修改的时候需要更新 \(now\) 位置以及前后最近的两个的和 \(now\) 相同颜色的位置的 \(pre\) 的值。然后就可以分块做了。

首先,对于修改操作,我们假设需要修改的区间为 \(l\)\(r\)。我们可以将操作分为三个部分。

  • \(l\)\(l\) 所在块的结尾。我们可以直接暴力地去修改这个区间的每一个数,因为这一段区间的长度最长为 \(s\),修改的时间复杂度为 \(O(s)\)

  • \(l\) 所在块的后一块到 \(r\) 所在块的前一块。对于每一块,我们都可以直接修改一整个块的信息(\(p\) 数组),不需要对每一个数进行修改。而一共最多有 \(n/s\) 个块,时间复杂度 \(O(n/s)\)

  • \(r\) 所在块的起点 到 \(r\) 。同理,这一段区间的长度最长也为 \(s\),修改的时间复杂度为 \(O(s)\)

接下来是查询操作,我们还是假设需要查询的区间为 \(l\)\(r\)。我们也可以将查询操作分为三个部分。

  • \(l\)\(l\) 所在块的结尾。我们可以直接暴力地去计算这个区间的每一个数,因为这一段区间的长度最长为 \(s\),修改的时间复杂度为 \(O(s)\)

  • \(l\) 所在块的后一块到 \(r\) 所在块的前一块。我们会维护一个 \(p\) 数组来记录每一个区间内的信息(修改时也会更新 \(p\) 数组), 这样就不需要对每一个数进行计算 ,只需要把每一块的信息加起来即可 。而一共最多有 \(n/s\) 个块,时间复杂度 \(O(n/s)\)

  • \(r\) 所在块的起点 到 \(r\) 。同理,这一段区间的长度最长也为 \(s\),查询的时间复杂度为 \(O(s)\)

于是这道题就做完了。