前言
怎么清一色 LCT 做法,还有一个看上去很麻烦的树剖+线段树合并,下面给一种好写好想的树上倍增双 log 做法。
题意
动态加边维护树的重心。
做法
根据经典结论,合并两棵树后新的重心会在原本两棵树的重心的路径上,所以可以考虑使用倍增或二分求出新的重心。具体地,将询问离线下来把树建出来,每次连接一条新边 (u,v)∣depu≤depv 时就是将 v 的树以 v 为根并到 u 上,这里令当前 u 所在的树的根为 rt,首先动态维护 siz,直接做是链加单点查,但是经典方法是将其差分后改为用树状数组维护单点加子树查。
接下来令 u 所在树原本的重心为 wcu,v 的为 wcv,lca←LCA(wcu,wcv),首先特判掉 wcu=lca∨wcv=lca 的情况,然后令 tu 为 lca 在 wcu 方向上的儿子,tv 同理,易得 siztu+siztv+1=sizrt,所以 min(siztu,siztv)<2sizu,而又有重心的判定 sizwc≥2sizu,所以可以直接判断出新的重心在 tu 的子树内还是 tv 的子树内,并可以判断出在哪一条链上,若 wcu=lca∨wcv=lca 就肯定在 wcu⇝wct 的路径上。
知道了新的重心在哪一条路径上就可以直接倍增了,找到深度最大的满足 2sizu≥sizrt 的 u 即为重心,注意特判两个重心的情况,即若 2sizu=sizrt 则 u 的父亲也是重心。两种询问使用并查集在修改时维护即可。
时间复杂度为 O(nlogn+mlog2n),瓶颈在倍增时的树状数组查询,空间树上倍增数组需要 O(nlogn)。
Code