主席树 + 倍增求 LCA.
显然不可能每次都老老实实栽一棵子树上去,我们每次只栽一个节点到大树中,代表这次栽的子树.
大树上每条边的边权就变成了儿子对应的根到父亲对应的根的距离,如图所示.
左边是大树的真实形态,红色的边是每次栽子树时加的边,黑色的边是模板树中原有的边.
右边是每次只栽一个节点上去得到的大树形态.
考虑如何在每次栽边后计算出右边新增加的边的权值.
记录下第 $i$ 次操作后,大树实际含有节点的总数 $s_i$ ,那么给出一个编号 $x$ 后,就可以二分出它是第几次被栽进来的.
若它是第 $i$ 次操作被栽进来的,那么 $k=x-s_{i-1}$ 就是它在第 $i$ 次被栽进来的所有点中,编号从小到大的位次.
即在模板树中,它是子树 $a_i$ 中所有节点编号的第 $k$ 小,用主席树可以查询出它在模板树中实际的编号.
对于每次操作,若栽在 $b$ 下面,就可以找出 $b$ 实际的编号,得到 $b$ 到那一次操作的 $a$ 的距离,再 $+1$ ,就是这次的边权.
询问 $(x,y)$ 时,尝试将它们跳到它们在大树上的 $lca$ ,跳的过程中累加跳过的距离.
先在右边的树上跳,若 $x,y$ 所属的代表节点没有祖先后代关系,当两者父亲相同时,说明已经被栽进了同一棵模板树.
此时将它们跳进模板树,再在模板树上询问两点的距离,加入答案.
若 $x,y$ 的代表节点有祖先后代关系,假定 $y$ 的代表是 $x$ 的代表的祖先,当 $x$ 跳到父亲是 $y$ 时,就可以跳进模板树了.
需要先预处理出父亲的倍增数组,加速跳的过程.
时间复杂度 $O(n\log n)$ .
其实这个结构与最后跳 $lca$ 的过程和圆方树有相似之处,对圆方树比较熟练的话应该不难写出.
1 | //%std |