题目描述
给出一棵包含
n
个点的森林。问按照以下规则行走,从
行走的伪代码如下:
count = 0
bool DFS( x, fa )
if ( x==v ) return 1
random_shuffle(e[x])
for each y in e[x] // which means that all the order of has the same possibility to be chosen
++count
if ( DFS( y, x ) ) return 1
++count
return -1
DFS( u, -1 )
要求实现
- 在
x
与
y 之间修建一条道路,若此前 x 与y 之间有路径相连则无视此次操作 - 若
x
与
y 之间存在一条直接相连的道路,则去掉之 - 询问从
u
走到
v 的期望步数
n≤105,Q≤2×105
分析
首先分析一下要求的期望步数是个什么东西。
读懂伪代码后发现它实际上是一个按照随机顺序遍历这棵树,直到遇到终点。
假如我们某一步走了岔路,那么显然要遍历完这条岔路对应的整一棵子树。那么在每一个点上我们只关注终点所在子树,以及它之前遍历的有哪一些子树。
不妨记
E(x)
表示从
x
走到
E(v)=0
从总体来看,
E(y)+1
这一项在
E(u)
中总共就恰好是
u
到
注意这一项
∑mk=0∑P,pk=y∑k−1i=02sizepi(m+1)!=∑mk=0∑P,pk=y∑k−1i=02sizepim!m+1=∑mk=0∑k−1i=02sizepik!∑pk+1⋯pm1(m−k)!m+1=∑mk=0∑k−1i=02sizepik!m+1
由于这里取遍所有的满足 pk 为通往终点的点的可能的顺序,观察一下
- 当 k=0 时,分子为 0
- 当
k=1 时,分子为 2sizex¯¯¯¯¯¯¯¯ - 当 k=2 时,分子为 4sizex¯¯¯¯¯¯¯¯
- ⋯
- 当 k=m 时,分子为 2msizex¯¯¯¯¯¯¯¯
于是这一项实际上是
m(m+1)sizex¯¯¯¯¯¯m+1=∑z≠ysizez
总的那一项,实际上就是以
u
为根的树,减去
所以我们需要维护的东西就很明确了
- 子树大小
- 连通性
- 支持动态加或删边
用LCT可以轻松解决后两个问题。
但是LCT怎么维护子树大小呢?
不妨记
linkx
表示当前形态的这棵树
x
代表的重链,最高的一个点的子树大小(注意这里要是指包括它本身和splay树的儿子所形成的一段重链)。
- 在
access 时,有可能将一个虚儿子变成重儿子,此时需要对 extra 和 link 做出一些调整- 在 splay 时需要对 extra 做出一些调整
- 加边时需要对 extra 做出一些调整
- 删边时需要对 link 做出一些调整
剩下任意的操作都不会对 extra 和 link 造成影响。
于是子树大小求出来了,剩下的就是LCT的常规维护了。时间复杂度 O(nlogn)
空间复杂度 O(n)