P5811 题解

problem & blog

题解代码都长得离谱,2k 代码了解一下!

如果我码风比较压行还可以 2k 以内,但是很不幸我是空格 + 大括号换行流


不妨设 \(a \le b \le c\),如果能使 \(C\) 联通,那么从中取出一个 \(A\)\(B\) 的连通块也是平凡的,所以只考虑 \(A,B\)

考虑树的情况。要找到一条边 \((u,v)\) 满足 \(u\) 那边的子树的 \(siz\ge a\)\(v\) 那边的子树的 \(siz \ge b\)

容易发现 \(a\le b\le \dfrac n2\),联想到重心,它的性质是 \(\forall siz\le \dfrac n2\),所以只需要枚举与重心相连的边,如果能找到一个子树把 \(A\) 塞进去,那么 \(n-siz>n-\dfrac n2>\dfrac n2\),很容易就能把 \(B\) 塞进去。找不到就是无解。

回到简单图。上面的 Special Task 提示我们建 \(\text{DFS}\) 树,并找到它的重心。下文令 \(siz_i\) 表示重心相邻的那些点的子树。

如果 \(\exists siz_i \ge a\),直接按照树的方法构造即可。否则,考虑第一个子树,有一些其他的子树会与它相连。如果这些相连的子树都算上了,还是没法干掉 \(A\),那么必须动用两次重心了,无解。

\(S\) 表示干掉 \(A\) 需要用到的点集。可以认为这个过程是一个一个看子树,当 \(\sum\limits_S siz_i\) 成功干掉 \(A\),立刻终止。由于 \(\forall siz_i < a\),故 \(\sum\limits_S siz_i < 2a\)。继续化简,\(n=a+b+c>2a+b>\sum\limits_S siz_i +b\),所以 \(b<n-\sum\limits_S siz_i\),也就是说必定可以干掉 \(B\)

输出即可。注意调换了 \(a,b,c\) 满足 \(a\le b\le c\) 后,输出也要调整一下。

代码,时间复杂度 \(O(n+m)\)

posted @ 2023-07-13 10:08  liangbowen  阅读(29)  评论(0编辑  收藏  举报