题解 P5397 [Ynoi2018] 天降之物
毒瘤卡常题。
考虑分块。先想查询。
对于块的内部,每个块预处理 $dis_{i,j,k}$,表示第 $i$ 个块内,$j$ 到 $k$ 的最短距离。这里得把 $j,k$ 在块内离散化,因为块长 $O(\sqrt{n})$,最多出现 $O(\sqrt n)$ 个值,空间是 $O(n\sqrt n)$ 的。
对于块到块,不难发现对于同一个值,仅每个块最靠左的位置和最靠右的位置才可能是优的。所以维护 $L_{i,j}$ 和 $R_{i,j}$ 分别表示第 $i$ 个块,值为 $j$ 最早出现位置和最晚出现位置。每个块扫一遍,贪心算一下即可。
想想修改。对于 $x$ 变成 $y$ 的修改,遍历所有整块。
-
若当前块没出现 $x$,直接跳过。
-
若当前块没出现 $y$,直接将 $x$ 对应的离散值传给 $y$。
-
若当前 $x,y$ 均出现,暴力更新关于 $x,y$ 所有信息。因为每次这样修改都会使块内的颜色少一,每次修改 $O(\sqrt n)$,最多修改 $O(\sqrt n)$ 次,共 $O(\sqrt n)$ 个块,所以时间复杂度还是 $O(n\sqrt n)$。
假设 $n,q$ 同级,时空复杂度都是 $O(n\sqrt n)$ 的。
难点在于卡常。几个比较重要的优化。
-
表示真实值和离散值映射关系的 $vis$ 数组和 $dis$ 数组大小都是 $O(n\sqrt n)$ 的,且值域都是 $O(\sqrt n)$,可以开
short,空间常数能少一半,效果明显。 -
内存访问一定要连续。内存访问连续对常数影响巨大。令 $vis$ 数组第一维表示值,第二维表示块的编号。其他数组都以块编号为第一维。
-
$L,R$ 数组以离散值为第二维,这样空间是 $O(n)$ 的。
-
$dis_{i,j,k}$ 保证 $j<k$,且尽量少调用 $dis$,因为它内存访问相当不连续。可以把 $i,j$ 压成一维,改为 $s_i+j$,我觉得效果不大。
-
随缘调调块长,我是 $370$。
-
用 C++20,只有一两个点差几十毫秒可以多交几发,利用评测机波动,或者利用 O2 性质来一些无谓的循环(我感觉会快,可能是假的)。
我半个小时交了四页,要有持之以恒的耐心。

浙公网安备 33010602011771号