CF1491H Solution
考虑分块。按照点的编号分块,维护 \(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)\)。
标签:cf1491h,重构,整块,solution,sqrt,异块,gets,根号 From: https://www.cnblogs.com/iorit/p/18040104