P4211 [LNOI2014] LCA
P5305 [GXOI/GZOI2019] 旧词
重看 P4211
求 \(\sum_{i=l}^{r} dep[LCA(i,x)]\),首先把 LCA 都求出来行不通,我们考虑转化计算贡献的形式,一个点的深度就是根到它的路径上的点的个数,两个点的 LCA 的深度就是根到这两点的路径上相交的点的个数,做法就出来了:
离线;依次加入点 \(i\) 的贡献,对应在根到 \(i\) 的路径上点权加 \(1\);对点 \(x\) 查询根到 \(x\) 路径上的点权和。
树剖线段树,时间复杂度 \(O(q \log n)\)。
这是上次集训时学长的讲法,“相交的点的个数”这种说法十分好理解贡献是如何转化的,但是我做 P5305 时突然觉得这种说法不够本质(可能是我脑子不好使)导致这个转化方式的拓展性受限,现在从树上差分的角度重新理解这个做法,顺便解决该题的加强版 P5305。
“一个点的深度就是根到它的路径上的点的个数”,这其实是一种树上差分,可以假设树上深度的差分值表示 \(a[i]=dep[i]-dep[fa_i]=1\),那么 \(dep[i]=a[rt]+....+a[fa_i]+a[i]\)。因为差分值正好是 \(1\) 自然有多少个点深度就是多少,那么原做法我们可以这样理解其正确性:
每次要加入 \(i\) 的贡献时,我们让根到 \(i\) 的路径上对应的每一个点 \(k\) 的点权都加上一次 \(a[k]\),假设 \(x\) 是查询时的一个点,经过这样一次操作后,根到 \(LCA[i,x]\) 的路径上所有点增加的点权和就是 \(dep[LCA[i,x]]\)。同理加入了一个区间内所有点的贡献后再对路径求和,得到的就会是 \(\sum_{i=l}^{r} dep[LCA(i,x)]\)。
P5305 题解
如果用一开始的视角去思考这道题会困在维护 \(k\) 次方和这一步,这是因为没有理解上一题中的点权 \(+1\) 指代的是差分值的出现次数而不是深度的覆盖次数之类的。
但用树上差分的视角去看这道题的操作会好理解许多。
现在题目变成求每个 LCA 的 \(k\) 次方深度的和,可以把差分值变成 \(b[i]=dep[i]^k-dep[fa_i]^k\),则求一下路径前缀和就可以得到 \(dep[i]^k\)。
加贡献时把路径上的每一个点加上 \(b[i]\),求和时就能够得到 \(\sum_{i=l}^{r} dep[LCA(i,x)]^k\) 了。
具体维护时可以用线段树预处理出每个区间的 \(b\) 值,路径加时直接加对应的 \(b\) 就好了。