cf1491h-solution

CF1491H Solution

link

考虑分块。按照点的编号分块,维护 \(b_i\) 表示 \(i\) 往上跳遇到的第一个与 \(i\) 异块的点。

对于散块修改,直接暴力重构整块的 \(b\)。重构方式是,如果 \(a_i\)\(i\) 异块,则 \(b_i\gets a_i\);否则 \(b_i\gets b_{a_i}\)

对于整块,打标记维护整体减了多少。一个好玩的点是,每次减的数至少是 \(1\),那么这个块减 \(\sqrt n\) 次会导致他们的 \(a_i\)\(i\) 异块,这时候 \(b_i=a_i\)

如果我们在每个整块被修改时都给它重构了,重构次数不会超过 \(\sqrt n\times \sqrt n=n\),因为我们不需要重构修改次数大于根号的点。这样的暴力修改总复杂度是 \(\mathcal O(n\sqrt n)\) 的。

如何询问 lca?我们可以采取与树剖类似的方式找 lca:

  • 如果 \(b_u\not =b_v\),令其中 \(b\) 较大的点执行 \(x\gets b_x\)

  • 如果 \(b_u=b_v\),令其中 \(a\) 较大的点执行 \(x\gets a_x\)

直到 \(u=v\)。这个算法显然是单次根号的。

最后复杂度 \(\mathcal O(n\sqrt n)\)

posted @ 2024-02-28 13:38  iorit  阅读(9)  评论(0)    收藏  举报