luogu P7446 [Ynoi2007] rfplca 题解
P7446 [Ynoi2007] rfplca
题意
给定一棵大小为 \(n\) 的 \(1\) 为根节点的树,树用如下方式给出:输入 \(a_2,a_3,\dots,a_n\),保证 \(1\leq a_i<i\),将 \(a_i\) 与 \(i\) 连边形成一棵树。
接下来有 \(m\) 次操作,操作有两种:
1 l r x令 \(a_i=\max(a_i-x,1)(l\leq i\leq r)\)。2 u v查询在当前的 \(a\) 数组构成的树上 \(u,v\) 的 LCA。
题解
我们发现\(i->a_i\),这个操作有些似曾相识,和P3203 [HNOI2010]弹飞绵羊有些类似。
同样的,我们使用分块算法,将序列分为\(\sqrt{n}\)块,对于块内每一个元素求出\(to_i\),表示第一个跳到其他块的编号。
但是这次我们求得是两点的\(lca\),发现我们往前跳的过程是在树上向上跳的过程,而且深度随编号递增,一次我们可以模仿树剖写出一个求\(lca\)的方法。
我们将跳到块外的操作称为大跳,跳到真正的父亲的操作称为小跳,\(x\)所在的块被成为\(in_x\)。
设当前两点为\(u,v(u<v)\),大跳后的点为\(x,y\),则:
1.\(x \neq y\),则\(v=y\)
2.\(x=y\),则\(v=a_v\)
到最后\(v=u\)时即为\(lca\)。
发现\(x,y\)实际上是\(u,v\)在树上的链顶,所以说这也就是树剖的过程。
每一次大跳会跳\(\sqrt{n}\)的长度,小跳至多跳\(\sqrt{n}\)次,时间复杂度\(\sqrt{n}\)。
考虑修改的过程,和另一题类似,如果一个点被修改了,那么就要将一个块重构。
如果修改整个块,那么我们先修改再重构就能保证时间复杂度,每个块修改一次的时间复杂度为\(\sqrt{n}\)。
重构的时候从左往右修改会简单很多,之前没有注意这个问题导致代码很臃肿。
但是还是不行,每个块修改一次\(\sqrt{n}\),每次修改\(\sqrt{n}\)个,依次修改就是\(O(n)\)的,显然不行。
每个点同时修改父亲这东西也太\(hard\)了,这题有没有什么特殊性质?
发现每一个数修改之后只会变小,则每个块内的数字最多被修改\(\sqrt{n}\)次后任意一点小跳一次就会出块。
所以每一个块最多被操作\(\sqrt{n}\)次,超过\(\sqrt{n}\)次之后就没必要对块内重构了,直接将大跳变成小跳也是没问题的,因为每次小跳也至少会跳过\(\sqrt{n}\)的距离,不比大跳劣。
然后就结束了,梳理一下:
1.对每个块内的数维护真实父亲,出块的父亲。
2.每次操作修改后暴力重构.若操作\(\sqrt{n}\)之后则不用重构。
3.用类似树剖的方式跳。
我们见到只增或只减的话,考虑分析每次增加或减少的势能。
感觉这个还是比较常见的,可惜看的时候没有想到。

浙公网安备 33010602011771号