Ynoi 做题记录

我是仙人掌

发现一共只有 \(n^2\) 个点对,询问时的形式类似集合并,考虑使用 bitset.

由于询问与距离有关,因此考虑将 \(x\)\(dis\) 作为两个维度,bitset 维护到 \(x\) 距离小于等于 \(dis\) 的点集.

预处理时使用 BFS 直接处理,查询时暴力合并 bitset.

时间复杂度为 \(O(\frac{n^3}{w}+\sum a\frac{n}{w})\),虽然看起来不可过,但是常数极小.

无力回天

维护 \(m\) 个集合,有集合添加,集合查询并.

我的做法

由于并集涉及元素过多,考虑使用容斥原理转化成交集.

我们发现如果暴力匹配,复杂度与集合大小相关,因此考虑离线,提前记录集合大小,考虑之后的算法.
由于元素一共只有 \(m\) 个,随着每个集合元素个数增加,集合个数减少,故考虑根号分治.
设定集合的大小阈值 \(L\),我们考虑使用两类暴力算法:一种是直接比较,另一种使用 bitset.

  1. 考虑对于集合大小小于 \(L\) 的元素,使用哈希表存储,添加 \(O(1)\).
  2. 考虑对于集合大小大于 \(L\) 的元素,使用 bitset 存储,添加 \(O(1)\).

考虑查询:

  • \(1\to 1\):在哈希表中暴力查找,复杂度为 \(O(L)\).
  • \(1\to 2\):在 bitset 中暴力查找,复杂度为 \(O(L)\).
  • \(2\to 2\):暴力合并 bitset,复杂度为 \(O(\frac{m}{w})\).

时间复杂度为 \(O(m(L+\frac{m}{w}))\),空间复杂度为 \(O(m+\frac{m^2}{Lw})\).

上面的太劣了,考虑优化.

我们没有很好利用集合大小大于 \(L\) 的集合个数只有 \(O(\frac{m}{L})\) 个.
考虑直接暴力记录 \(O(\frac{m}{L})\) 个集合之间的贡献,
在每次添加元素时,对另外 \(O(\frac{m}{L})\) 个元素暴力统计,时间复杂度为 \(O(\frac{m}{L})\).
查询时 \(O(1)\).

时间复杂度为 \(O(m(L+\frac{m}{L}))\),空间复杂度为 \(O(m+\frac{m^2}{L^2}+\frac{m^2}{Lw})\).
\(L=\sqrt{m}\) 较优,由于常数原因,取 \(L=\frac 12\sqrt{m}\) 更优.

事实上还可以继续优化常数:
我们不使用哈希表存储,使用 vector 存储(由于我们已知集合大小,因此可以提前 reserve,减少常数).
每次插入一个元素,对 vector 进行插入排序,时间复杂度为 \(O(L)\).
每次询问 \(1\to 1\) 时,由于集合时有序的,因此可以使用双指针统计,时间复杂度为 \(O(L)\).
常数大大减小.

洛谷常见做法

对值的出现次数进行根号分治:设定阈值 \(B\).
对于值出现次数大于 \(B\) 的元素,会有 \(O(\frac{m}{B})\) 个,对于每个集合维护一个 bitset 维护这些数,查询 \(O(\frac{m}{Bw})\),修改 \(O(1)\).
对于值出现次数小于 \(B\) 的元素,统计集合之间的贡献,至多会有 \(O(mB)\) 个贡献,使用哈希表存储,查询 \(O(1)\),修改 \(O(B)\).

\(b=\sqrt{\frac{m}{w}}\),有最终时间复杂度为 \(O(m\sqrt{\frac{m}{w}})\),空间复杂度为 \(O(m\sqrt{\frac{m}{w}})\).
但是哈希表的常数~

posted @ 2026-07-24 09:35  zhoumengxuan  阅读(7)  评论(0)    收藏  举报