前言

赛时四发罚时直接葬送 perf,写完还以为是个脑子题,过的人肯定不多。

累了,能不能数据加到 n107n\leq 10^7 把写 nlogkn\log k 的都叉掉(虽然我当时降智地使用了《倍增》来求树上 kk 级祖先)。

思路

把每个 iixix_i 连边,形成一张 nn 个点 nn 条边的有向图。

由于每个点出度均为 11,这张图实际上是内向基环树森林。

观察到进行 kk 次操作对 aia_i 的影响实际上就是以 ii 为起点在图上走 kk 次。

那么可以分类讨论两种情况:kk 次操作后,第 ii 个点在环上 / 不在环上。

首先拓扑排序一遍找出所有在环上的点,dfs 出每个环的大小并对每个环上的节点从 00 开始进行标号。设某个环的大小为 ss,手玩发现如果已经走到了该环上的第 ii 个节点,还需要走 xx 步,则最后一定落在环上的第 (i+x)mods(i+x)\mod s 个节点。于是直接从环上的每个节点出发再 dfs 一遍,预处理出每个不在环上的节点将会到达的环上节点与需要走的步数即可。

那么对于 kk 步后走不到环上的情况呢?这个问题等价于求树上每个点的 kk 级祖先。你当然可以用各种树剖科技或使用另一种解法中的倍增来求解这个问题,但本题的 kk 是固定的,你只需要在 dfs 时维护一个双端队列(类似单调队列)。具体地,队列里保存了所有与当前节点深度差 k\leq k 的节点,当队列大小 >k>k 时,弹出队头,队头即为当前节点的 kk 级祖先,处理完当前子树后再将队列还原。

那么这题就用 O(n)\mathcal{O}(n) 的复杂度做完了。

代码

link,64ms。