圆方树
T1. P4320
对于无向连通图来说,最好的办法就是转化为圆方树。根据圆方树的性质任意两个方点之间必定有圆点链接,这个圆点就是这两个点双的割点。
重新观察题目,我们发现题目要求的就是求 \((u,v)\) 之间的割点个数,也就是在树上路径 \((u,v)\) 之间求出圆点的个数。由于 \(u\) 和 \(v\) 皆为圆点,那么答案就是 \(\lfloor \dfrac{路径 u,v 的长度}{2} \rfloor + 1\)。
T2. P4606
这个是上一题的升级版。
显然用上一题的方法,这题是过不去的。考虑优化。
我们把圆点的贡献计为 \(1\),方点的贡献计为 \(0\),一条路径的贡献就是路径上所有点的贡献。那么就是要求两点的路径的贡献。
套路的我们把点按照 dfs 排序,然后从 \(1\) 号点出发,走到 \(s\) 号点后再绕回来,每两个点中间我们就统计答案即可。
特别的,\(1\) 号点和 \(s\) 号点的 LCA 可能不会被计算到。如果这两个点的 LCA 为圆点,那么答案就加上 \(2\) 即可。
T3. P4630
先考虑特殊情况,及在树的情况。
我们考虑枚举 \(u\),那么分别从 \(u\) 的两个不同的子树中任选出 \(2\) 个点,这 \(2\) 个点必定是合法的 \((s,f)\)。
那么一个点 \(u\) 对于答案的贡献就是 \(\sum_{v \in son_u} siz_v \times (siz_u - siz_v - 1)\)。
大么对于无向图来说,我们先考虑建出圆方树。
对于圆点的处理是相同的,但是方点也有贡献,此时我们考虑方点的贡献。
方点的贡献就是一个子树中的点会途经这个点双后到达另一个子树中的点。
那么对于一个方点的贡献就是 \(\sum_{v \in son_u} siz_v \times (siz_u - siz_v) \times (deg_u - 2)\)。
T4. P4244
我们考虑使用类似于求树的直径的方法来求仙人掌的直径。
我们定义 \(dp_u\) 为以 \(u\) 为链的顶点的最长链的长度。那么分为以下两类情况:
- \(u\) 不在任意一个环上
那么此时我们直接使用正常的树形 dp 来解决即可。那么就有 \(ans = \max(ans,dp_u + dp_v + 1),dp_u = \max(dp_u,dp_v + 1)\)。此时的 \(u \to v\) 必定是一条割边。
判定方法就是 \(v\) 不能通过返祖边走到 \(u\) 的上面,即为 \(dfn_u < low_v\)。
- \(u\) 在环之上
面对带有环的问题,先考虑破环为链。那么我们先把这个环拎出来后把他复制以一边。
那么我们现在的任务就是求出两个点 \(i,j\) 满足 \(1 \le i,j \le 2 \times len,0 < j - i \le \lfloor \dfrac{j - i}{2} \rfloor\) 使得 \(dp_j + dp_i + j - i\) 最大。此时考虑我们固定 \(j\),然后求出最大并且满足一以上条件的 \(dp_i - i\)。此时我们可以使用单调队列来维护。
T5. uoj 158
对于一个圆方树,我们考虑把点分成 \(3\) 类:
-
方点和方点的儿子为第 \(0\) 类。
-
在环上,方点的重儿子到方点的父亲的最短路径中出现的点为第 \(1\) 类。
-
在环上,方点的重儿子到方点的父亲的最长路径中出现的点为第 \(2\) 类。
接着要安排点的顺序。此时对于一个环,要把所有环上的点都放进来,再去考虑子树。
对于一个方点,先依次把它自己和它的所有儿子加入 dfs 序中,然后再按照重边先行的顺序访问儿子的子树。对于一个圆点,直接按照重剖即可。
对于操作一,路径上只会有第 \(0\) 和第 \(1\) 类点出现。而对于操作二,路径上只会有第 \(0\) 和第 \(2\) 类点出现,并且这些点的 dfs 序中间没有未经过的同类点。
那么我们就考虑用一颗线段树维护这三个信息即可。
代码还是比较难写的。