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.用类似树剖的方式跳。

我们见到只增或只减的话,考虑分析每次增加或减少的势能。
感觉这个还是比较常见的,可惜看的时候没有想到。

posted @ 2023-05-12 16:22  谭皓猿  阅读(24)  评论(0)    收藏  举报