logo

yaohaoyou

春节

P4299 首都 题解

2025-11-19 Views 题解 | 树上问题561字3 min read

题目传送器

更爽的阅读体验

前言

怎么清一色 LCT 做法,还有一个看上去很麻烦的树剖+线段树合并,下面给一种好写好想的树上倍增双 log\log 做法。

题意

动态加边维护树的重心。

做法

根据经典结论,合并两棵树后新的重心会在原本两棵树的重心的路径上,所以可以考虑使用倍增或二分求出新的重心。具体地,将询问离线下来把树建出来,每次连接一条新边 (u,v)depudepv(u,v)\mid dep_u\le dep_v 时就是将 vv 的树以 vv 为根并到 uu 上,这里令当前 uu 所在的树的根为 rtrt,首先动态维护 sizsiz,直接做是链加单点查,但是经典方法是将其差分后改为用树状数组维护单点加子树查。

接下来令 uu 所在树原本的重心为 wcuwc_uvv 的为 wcvwc_vlcaLCA(wcu,wcv)lca\gets \operatorname{LCA}(wc_u,wc_v),首先特判掉 wcu=lcawcv=lcawc_u=lca \vee wc_v=lca 的情况,然后令 tutulcalcawcuwc_u 方向上的儿子,tvtv 同理,易得 siztu+siztv+1=sizrtsiz_{tu}+siz_{tv}+1=siz_{rt},所以 min(siztu,siztv)<sizu2\min(siz_{tu},siz_{tv})<\frac{siz_u}{2},而又有重心的判定 sizwcsizu2siz_{wc}\ge \frac{siz_u}2,所以可以直接判断出新的重心在 tutu 的子树内还是 tvtv 的子树内,并可以判断出在哪一条链上,若 wcu=lcawcv=lcawc_u=lca\vee wc_v =lca 就肯定在 wcuwctwc_u\leadsto wc_t 的路径上。

知道了新的重心在哪一条路径上就可以直接倍增了,找到深度最大的满足 2sizusizrt2siz_u\ge siz_{rt}uu 即为重心,注意特判两个重心的情况,即若 2sizu=sizrt2siz_u=siz_{rt}uu 的父亲也是重心。两种询问使用并查集在修改时维护即可。

时间复杂度为 O(nlogn+mlog2n)\mathcal O(n\log n+m\log^2n),瓶颈在倍增时的树状数组查询,空间树上倍增数组需要 O(nlogn)\mathcal O(n\log n)

Code

EOF