2022.8.5 闲话
发现一个很好玩的东西,
Problem 1
维护一个森林,要求支持:
- 选中一个节点,求这个节点所在树的直径 .
- 选中两棵树,连接一条能使得两棵树连接后直径最小的边 .
所有边权都为 1 .
题目来源 .
合并直接并查集,初始的直径先预处理一波 .
观察操作 2,发现一个很显然的结论,就是两棵树中的直径中点连边,连后的直径最小 . 然后观察这两棵树的最长链上的节点个数:
- 如果两个都是奇链,合并后的中点选合并前的中点的任意一个就可以 .
- 如果一个是奇链,一个是偶链,合并后的中点选偶链上的那个中点 .
- 如果两个都是偶链,合并后的中点选合并前的中点的任意一个就可以 .
设连结前 A 树的直径为 \(d_a\),B 树的直径为 \(d_b\)。很显然,合并后的直径为 \(d_c = \left\lceil\dfrac{d_a + 1}{2}\right\rceil + \left\lceil\dfrac{d_b + 1}{2}\right\rceil\) .
然后在并查集上进行合并和信息向上传递即可 .
以下所有边权都是正数 .
Problem 2
维护一个森林,要求支持:
- 选中一个节点,求这个节点所在树的直径 .
- 选中两棵树,连接一条能使得两棵树连接后直径最长的边 .
看起来和 Problem 1 十分相似,但实际上这题简单很多(口胡)
结论:两棵树 \(\mathcal T_1,\mathcal T_2\) 的直径分别是 \(u\leftrightarrow v\),\(x\leftrightarrow y\),则用一条边将两棵树连接后,新直径的端点必然在 \(\{u,v,x,y\}\) 中 .
关于加边动态直径见 Problem 4,这里先放着(伏笔)
Problem 3
给你一棵树,要求支持:
- 查询子树直径长度 .
- 删掉一个子树 .
注意到子树操作,于是考虑 DFS 序维护 .
当我们删除一个在 DFS 序上连续的区间时,考虑把两个区间进行合并,这样就是 Problem 2
的结论了 .
合并只需快速计算两点间距离,等价于快速 LCA .
这样最快能做到 \(O(n)\) 预处理 \(O(1)\) 操作 .
当然作为一个正常人谁写标准 RMQ 啊,但是也别傻乎乎地写倍增,朴素 RMQ 是单次询问 \(O(1)\),预处理 \(O(n\log n)\) 的,不知道比倍增高到哪里去了 .
Problem 4
给你一个森林,要求支持:
- 加一条边,保证加完还是树 .
- 求全局直径 .
注意到加边,于是考虑 LCT .
用 Problem 2 的性质,只需维护直径端点 .
加边就 LCT 暴力干即可,\(O(n\log n)\) .
自带 6 倍常数,还得加上 LCT 巨大常数,刺激!
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16555690.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ