「笔记」长链剖分
树有很多种剖分。
常见的是重链剖分。
然而还有针对树深度信息维护的长链剖分。
和重链剖分类似。
长链剖分维护长链,同时也有长儿子和短儿子。
所有长链长度之和为\(n\),这个显而易见。
那么我们在维护和长度相关的信息的时候。
一般情况下是将儿子的长度位移,这样的话可以直接用指针数组继承长儿子的信息。
同时暴力统计短儿子的信息。
这样每条长链最多被扫一次。
复杂度就是完美的\(O(n)\)。
T1.\(Hotel\)加强版
我们设\(f[x][i]\)为距离\(x\)的长度为\(i\)的点的个数,\(g[x][i]\)为有两个点在\(i\)的子树中,且其到达他们的\(LCA\)的距离为\(d\),他们的\(LCA\)距离\(x\)的长度为\(d-i\)的点对个数。
那么有:
\[ans+=g[x][0]+g[x][i]*f[t][i-1]+f[x][i]*g[t][i+1],f[x][i]+=f[t][i+1],g[x][i]+=g[t][i-1]
\]
然后这个东西直接做复杂度是\(O(n^2)\)的。
考虑用长链剖分优化。
我们发现后面的转移其实都是一个位移。
我们用指针实现对长儿子的\(shift\),然后短儿子就暴力扫短儿子内部的最大深度。
这样每个长链就被扫一次,复杂度就是\(O(n)\)的。
T2.谈笑风生
我们发现其实只需要关注\(a,b\)的情况。
1.\(a\)在上\(b\)在下,这个时候统计距离\(a\)的长度小于\(k\)的\(b\)的\(sz_b-1\)的和就可以了。
2.\(b\)在上\(a\)在下,这个时候统计\(a\)的满足限制的祖先个数即可。
第二个很简单。
考虑第一个用长剖维护。
\(dp[i][j]\)为距离点\(i\)的长度为\(j\)的\(sz_b\)和。
那么前缀和不好维护,维护一个后缀和就可以\(O(n)\)的\(dp\)了。