省选图连通性与圆方树专题做题记录
A CF51F Caterpillar
\(\text{Link}\)
考虑到毛毛虫上不能有环,所以第一步肯定是先把环搞掉。于是我们先进行边双连通分量缩点,每个边双连通分量需要其大小减一步合并为一个点。现在图变成了一棵树,考虑树怎么合并。发现我们需要找到一条主链,然后把主链上外挂的节点合并。现在我们需要让合并次数最小,首先发现叶子节点永远不用合并,其次主链上的节点也不用合并。那么自然我们要让主链上节点个数最多,选直径即可。
最后我们还要将若干连通块合并起来,只需要再花费连通块个数减一步即可。复杂度 \(O(n+m)\)。
B CF475E Strongly Connected City 2
\(\text{Link}\)
首先我们发现环上的点一定可以互相到达,于是我们先对图进行边双连通分量缩点,这样对于每一个边双,其贡献为 \(siz^2\)。接下来考虑在树上如何定向,手玩样例发现这样一个性质:一定存在一种最优解,使得存在一个点,以它作为根,一部分子树全部指向根,另一部分子树全部指向叶子。
考虑枚举这个点,先用树形 dp 算出来每个子树内部到子树根的贡献,因为这一部分贡献和最终它指向哪没有关系。然后接下来我们需要看怎样划分子树,假如两个部分的子树和分别为 \(x,y\),则多出来的贡献就是 \(x\cdot y\)。考虑直接枚举 \(x\),然后我们用一个背包判断一下即可。这样背包的复杂度是 \(O(\sum deg_i\times n)=O(n^2)\) 的,于是我们就可以在 \(O(n^2)\) 的复杂度内解决这个问题。
C CF855G Harry Vs Voldemort
\(\text{Link}\)
首先我们先考虑树的情况怎么做,不难发现我们可以钦定 \(w\) 的位置,这样 \(u,v\) 就必须在以 \(w\) 为根的不同子树中。考虑利用容斥计算方案数,发现方案数就是 \((n-1)(n-2)-\sum siz_{to} (siz_{to}-1) - (n-siz_w)(n-siz_w-1)\)。其中 \(siz_x\) 表示 \(x\) 子树内点的个数。
然后考虑如果动态加边怎么做,不难发现此时会形成边双。而如果 \(w\) 在边双中,\(u,v\) 均在边双中是合法的,并且 \(u,v\) 只有一个在边双中同样是合法的。因此我们需要减掉的不合法情况依然只有上面的部分。所以对于一个边双 \(x\),其贡献为:
其中 \(s_x\) 表示 \(x\) 的边双大小。现在我们需要在树上动态维护边双,可以考虑使用并查集,每次我们相当于把一条链上的点缩成一个点,那么用并查集维护这些点中深度最小的点即可。这个过程可以直接暴力跳父亲做到,并且可以顺便维护出 \(s_x\) 与 \(\sum siz_{to}(siz_{to}-1)\)(不用维护 \(siz_x\) 是因为 \(siz_x\) 缩点后不变),然后答案就不难求了。由于每个点只会被缩一次,所以暴力合并的次数是 \(O(n)\) 的,总复杂度 \(O(n)\)。
D BZOJ3331 [Beijing2013] 压力
看到题目中所说的限制,不难想到割点。于是直接建圆方树,那么两个点之间所有的圆点都是必须要经过的,树上差分一下即可。复杂度是 \(O(n\log n)\) 的。
E CF1763F Edge Queries
\(\text{Link}\)
首先这个性质其实是无用的。考虑到点双中总有两条点不相交路径,所以如果我们要经过一个点双,我们可以将这个点双中的任意一条边割掉,而不会影响 \(a,b\) 连通性。所以考虑建立圆方树,圆点权值为 \(0\),方点权值为该点双内部边个数。那么我们只需要统计出 \(a\to b\) 中所有点的点权之和就是答案。依然可以使用树上差分统计。
不过实际上点双并不总是满足上面的性质,因为有可能出现两个点连一条边的情况,此时这条边不能割掉,所以我们需要特判一下。总复杂度 \(O(n\log n)\)。
F CF487E Tourists
\(\text{Link}\)
首先发现我们要走的是 \(a\to b\) 的简单路径,因而不能经过重复的城市。于是不难想到只有对于一个点双我们才能走到它里面任何一个点,考虑建圆方树解决这个问题。
一个直接的思路是记每个圆点的权值为它的 \(w_i\),方点的权值为与之相邻的圆点的 \(w_i\) 的最小值。先考虑如果修改了一个圆点,如何维护周围方点的变化,显然这可以直接用一个 multiset
解决。不过问题在于如果我们每次对于一个圆点将与其相连的方点全部修改一遍的话,我们就会被菊花图卡到 \(O(n^2)\)。
考虑到圆方树本质还是一棵树,树是长于维护每个点的子树信息的,所以修改方点权值定义为其所有儿子圆点的 \(w_i\) 最小值。如此会发现我们求答案的过程几乎没有影响,唯一需要改变的是特判 \(\text{LCA}\) 处是不是方点,是的话需要加上其父亲圆点的权值进行计算。这样我们每次只用修改一个方点的信息,修改的复杂度就可以承受了。最后的总复杂度为 \(O(n\log^2 n)\)。
G P4630 [APIO2018] 铁人两项
\(\text{Link}\)
发现这道题和 C 题有一定相似之处,考虑相同的思路。发现此题的不同点在于它不能经过重复点,所以考虑建立圆方树解决这个问题。下面我们称两个圆点相邻当且仅当两个圆点与同一个方点相连。
我们考虑枚举中转点 \(c\),那么会发现剩下的两个点 \(s,f\) 必须在不同的与 \(c\) 相邻的圆点子树内。我们考虑做树形 dp,此时 \(c\) 子树内的相邻圆点的贡献是可以直接计算的,但是 \(c\) 子树外的贡献没有办法直接在 \(c\) 处计算。这其实也很好办,我们在 \(c\) 的父亲方点处将剩下的贡献累加上去即可。式子和 C 题是一样的,直接转移即可。复杂度 \(O(n)\)。
H P4244 [SHOI2008] 仙人掌图 II
\(\text{Link}\)
首先我们先回顾一下树的直径怎么求,众所周知的有三种常用做法:两次 DFS、两数组树形 dp 和单数组树形 dp。第一个在仙人掌上难以使用不考虑,后面两个显然单数组更容易一点。先建出圆方树,考虑设 \(dp(u)\) 表示 \(u\) 向其子树内能延伸的最长路径。那么这时的重点就是环上的转移,我们把它放到方点上完成。
先把环上的节点提取出来,断环为链,这样我们只需要正着倒着各跑一下即可。令 \(f(u)\) 表示 \(u\) 在环上能走出的最长路径,则直径应该是 \(\max\{f(u)+dp(u)\}\)。考虑转移,显然这里有一个限制就是两个点之间的距离不能超过 \(\lfloor\tfrac m2\rfloor\),其中 \(m\) 为环上点的个数,所以有转移方程:
显然这个转移可以用单调队列优化。接下来更新完直径之后,我们还要用当前算出的 \(f\) 去更新方点父亲圆点的 \(dp\) 值,原因显然。于是我们就可以在 \(O(n)\) 的复杂度内解决这个问题。
I P6998 [NEERC 2013] Cactus Automorphisms
\(\text{Link}\)
首先考虑无根树同构怎么做。经典的做法就是取树的重心,然后把它看作根,这样问题就转化为有根树同构。接下来我们用树哈希计算每一个子树内的哈希值,然后在每一个节点处统计答案。我们将子树划分成若干同构的等价类,那么每一个等价类之内都可以互换,所以乘上每个等价类阶乘即可。
现在考虑放到仙人掌上怎么做。先建出圆方树,不难想到我们可以在圆方树上进行类似的过程。先找出重心定为根,然后不同点在于我们需要分类讨论圆点和方点的方案数:
- 如果是方点且在重心,那么这个环可以旋转或反折,我们现在就要找出旋转或反折后有多少种情况和原来的序列是一致的,我们断环为链,然后跑一边 KMP 即可得出方案数。注意特判只有两个点的情况,此时反折和旋转是一样的。
- 如果是方点但不在重心,那么这个环只能反折,所以其所有儿子构成的序列应该是一个回文串,暴力判断一下即可。注意此时一定要保证儿子是按照在环上出现的顺序排列的,并且要特判只有一个儿子的情况。
- 如果是圆点,那么按照上面的方式计算等价类即可。
但是这还没完,因为非重心方点的哈希值是不能直接将所有儿子的哈希值加起来算的,原因在于环上节点不能旋转,只能反折,所以必须要按一定的顺序哈希,解决方法也很简单,我们给每一位哈希后再乘一个 \(p^i\) 保证它有序,然后取正反两次哈希值结果的最小值作为它的哈希值即可。这样就可以保证判断环同构的正确性了。
最后输出答案的方式比较奇特,不过发现上面的所有方案的贡献都是乘在一起的,所以直接暴力算一下质数的贡献即可。精细实现一下可以做到 \(O(n)\) 的复杂度。
J P5966 [POI2016] Hydrorozgrywka
\(\text{Link}\)
首先先建出圆方树,既然这是道博弈题那么肯定要考虑 dp。不过在仙人掌上博弈和在树上博弈有一个区别:仙人掌会走回到根节点然后再决策。为了将这一部分贡献统计上,我们需要设三个状态:
- 先手从该节点开始走必败,或者会返回根节点但下一步仍然是自己走,那么先手完全没有必要走这个子树。
- 先手从该节点开始走必胜,那么直接走这个子树即可。
- 先手从该节点开始走可以走回到根节点,并且下一步可以让后手走。这相当于我们在这个节点决策时可以选择转化先后手。而在一个博弈游戏中,如果我们可以转化先后手且后续决策不变,那么先手必胜。
记上面三种状态为 \(f(x)=0/1/2\)。下面开始考虑转移。先考虑方点的转移,按照在环上走一圈的策略来看,只有当第一次走到 \(f(v)\ne 0\) 的节点时是先手先手才必胜,那么我们枚举一下儿子算一下,如果从左往右和从右往左有一个可以让先手必胜则 \(f(x)=1\),否则 \(f(x)=0\)。
一种特殊情况是儿子没有 \(f(v)\ne 0\) 的点,此时我们看整个环是不是奇环即可,如果是则 \(f(x)=2\),否则 \(f(x)=0\)。同时还要注意特判两点一边的情况,此时 \(f(x)=[f(v)=0]\)。
然后考虑原点转移,如果它的儿子中有 \(f(v)=1\) 那么 \(f(x)\) 必然等于 \(1\)。否则我们就看当前节点能否转化先后手,根据经典博弈结论,只有当 \(\sum [f(v)=2]\) 是奇数时才有可能,因为在先手转化完后,对面每转化一次先手都可以再转化一次来撤销,所以当 \(2\mid \sum[f(v)=2]\) 时 \(f(x)=0\),否则 \(f(x)=2\)。
那么我们就可以求出根节点的胜负状态,做一下换根 dp 即可 \(O(n)\) 求出答案。
K P3180 [HAOI2016] 地图
\(\text{Link}\)
不难发现如果我们建出圆方树后,问题就是求一个点的子树内有多少个满足条件的点。那么显然考虑维护权值线段树,对每个区间维护出现奇数次和偶数次的权值个数,然后做一下线段树合并即可。可以先离线然后合并时就不用新建节点了,复杂度 \(O(n\log n)\)。
另一种做法是用树上莫队,统计答案如果直接用树状数组的话是 \(O(n\sqrt n \log n)\) 的,把树状数组换成值域分块平衡复杂度就可以做到 \(O(n \sqrt n)\) 了。
L P9194 [USACO23OPEN] Triples of Cows P
\(\text{Link}\)
不难发现,删去一个点之后周围的点会变成一个完全图。那么直接用完全图做边数显然会炸,考虑利用圆方树的思想,我们现在将一个完全图进行缩点,在它中间建一个方点连边。初始的时候任意相连两点之间都有一个方点。
接下来先考虑统计答案,显然分方点圆点考虑。方点处理同一环上贡献,圆点处理不同环上贡献。
-
对于圆点 \(x\):
显然我们可以从它的任两个儿子方点中选出两个圆点构成三元组,那么设 \(f_x\) 表示方点 \(x\) 的儿子个数,则当前圆点贡献就是 \(\sum\limits_u \sum\limits_v f_u f_v\)。那么显然这个可以写成 \((\sum\limits_u f_u)^2-\sum\limits_u f_u^2\)。记 \(g_x=\sum\limits_u f_u\)。
-
对于方点 \(x\):
我们还需要进一步分类在同一个环上的节点个数。
-
如果三个点都在环上:
由于周围点的个数总共 \(f_x+1\) 个,所以方案显然为 \((f_x+1)f_x(f_x-1)\)。
-
如果只有两个点在环上:
我们需要先选出一个儿子圆点,在这个圆点的儿子中再选一个有连边的点。这一部分的方案数是 \(\sum\limits_u g_u\) 的,乘上选另一个圆点的方案数为 \(f_x\times \sum\limits_u g_u\)。由于这个式子是规定了顺序的,所以还要再乘一个 \(2\)。所以这种情况的贡献就是 \(2f_x\times \sum\limits_u g_u\)。记 \(h_x=\sum\limits_u g_u\)。
-
整合上述贡献,发现最终答案为圆点的 \(g_x^2\) 之和,以及方点的 \((f_x+1)f_x(f_x-1)-f_x^2+2f_xh_x\) 之和。考虑删去一个点的影响,显然会影响它父亲方点的 \(f,h\),它父亲的父亲圆点的 \(g\),以及它父亲的父亲的父亲方点的 \(h\),直接暴力修改上述值即可。接下来需要将该点的所有儿子方点和父亲方点合并,用并查集维护一下方点连通性即可。复杂度 \(O(n)\)。
M P9167 [省选联考 2023] 城市建造
\(\text{Link}\)
首先根据题目描述可以得到结论:如果同时选了某两个点,那么这两个点的所有简单路径上的点都要选,否则它们必然在同一连通块内。于是可以知道一个点双中如果选了两个点,那么这个点双中所有点都要选。考虑建立圆方树,令一个方点被选表示这个点双被选。接下来还有一个显然的性质:如果有两个方点被选,那么这两个方点路径上所有方点都要选。
根据上面两个性质可以推出一个引理:以重心为根时(注意这里子树大小只算圆点,下同),如果一个方点被选,那么它根链上所有的方点都要被删去。证明的话可以考虑从重心子树大小不超过 \(\tfrac{n}{2}\) 出发,如果根节点的一个子树内的某个方点被选,那么根节点一定有另一个子树的方点被选,否则不满足相差不超过 \(1\);根据上面的性质可以知道此时两者的根链都要选。并且还可以知道重心方点一定要选。
接下来分类讨论 \(k=0/1\),枚举连通块大小,如果 \(i\) 是圆点,则 \(f_i\) 表示选 \(i\) 的父亲方点的合法方案数;否则 \(f_i\) 表示选了 \(i\) 的合法方案数。接下来讨论即可,根据上面的引理,如果当前点的某个子树要被割掉,那么其儿子节点一定会被割掉,那么根据连通块大小上限直接转移即可。最终答案就是 \(f_{rt}\),其中 \(rt\) 是重心。
注意 \(k=1\) 时有可能会把所有连通块大小相等的情况算两次,需要减掉。复杂度是 \(O(n\sqrt n)\) 的,\(O(\sqrt n)\) 是枚举连通块大小的复杂度。