AGC009D - Uninity 题解

给定 \(n\) 个点的树,求其点分树的最小可能的深度。

\(n\leq 10^5\)

第一个想法是,直接枚举分治中心,然后分裂成若干个连通块,递归下去。这就是个状态数是连通块子图数量的 DP,模拟赛可能能写个记忆化骗个分啥的,正解就不用想了。

我们发现这样正常做完全没思路。我们必须转化,我们必将转化。

intended 的考虑是:给每个点标号 \(d_i\),代表它在点分树上的深度,求所有合法标号方案的最大标号的最小值。对如何想到这个的,我有两点理解:

  • 换贡献体。直接考虑以点的深度序列为贡献体,自然就能想到标号。
  • 或者直接认为对节点进行标号就是一种常规的套路,也不是不行,类似于染色法。

我们来考察一个标号方案的合法性的判定。考虑堆砌必要条件。对于两个点 \(x,y\),它们之间的链上肯定有一个点,是第一次分裂它们的点,也就是在点分树上的 LCA。如果 \(d_x\neq d_y\),那完全可以令深度小的那个当 LCA,没什么结论;而如果 \(d_x=d_y\)\(\{x,y\}\) 之间的任何一个都不可能是 LCA,那只能是链中间的。那么就得到了一个看上去挺强的必要条件:对所有 \(d_x=d_y\),它们的简单路径上必须存在 \(z\) 满足 \(d_z<d_x\)

我们来试图证明其充分性:尝试根据 \(d\) 还原点分树。首先找到 \(d_x=0\)\(x\),它显然最多有一个(因为没有小于 \(0\) 的标号),而如果没有的话一定不优,所以 \(x\) 存在且唯一。然后归纳到分裂的若干连通块,只不过最小值为 \(1\)。就这样递归下去,每递归一层最小值就增加 \(1\),一定能构造出点分树。


现在我们开始全身心最小化合法标号方案的最大标号。考虑树形 DP 的话,需要记录子树对外界的影响:只需要用一个 mask,记录从根往下的所有前缀最小值。注意到由于答案是 \(\mathrm O(\log n)\) 级别,所以这个 mask 只有 \(\mathrm O(n)\)。但仍然无济于事,先不说 DP 的转移非常复杂,状态数本身就要 \(\mathrm O(n^2)\) 了。

容易想到二分答案 \(L\),限制最大标号不超过 \(L\),这样问题看似直接降了一个维度,而只付出了 \(\mathrm O(\log\log n)\) 的代价。我们还是要记录一个 mask,而 DP 值变成了 bool 表示是否可行。看起来还是没什么用。

我们注意到:在二分答案之前,叶子处的决策是不确定的;而如今确定了 \(L\),那么叶子肯定贪心地选 \(L\),留给上面最多的选择空间。至少在叶子处,DP 的决策是唯一的,局部退化为了贪心。而如果非叶节点的决策也是唯一的,整个 DP 就完全退化为了贪心,不需要再以 mask 为状态,直接记录贪心得到的 mask 即可。这就是说,贪心本质上是每处决策都唯一的退化版 DP

于是我们来具体看看非叶节点的转移。假设所有儿子的 mask 已经确定,设为 \(S_{1\sim k}\),如果此时能够找到 \(d_x=u\) 的严格最优解,就得到了贪心。首先,对于同时出现在两个 \(S_i,S_j(i\neq j)\) 里的 \(v\),必须要有 \(u<v\),这就得到了一个限制 \(u\leq u_0\)。然后再考虑 \(x\) 自身与子树里的标号也不能违反条件,具体来说就是必须有 \(u\notin \bigcup_i S_i\)。这样 \(x\) 处新的 mask 就是 \(S=\{u\}\cup(\bigcup_i S_i\cap [0,u))\)

我们能比较选不同的合法的 \(u\) 时,得到的 \(S\) 的严格优劣吗?直觉告诉我们,类似于叶子,\(u\) 应当越大越好,这样看似能留给上面最多的选择空间。稍加思考,发现八九不离十。考虑 \(v=\mathrm{mex}(S)\)\(S\) 今后第一个可能可选的标号,我们发现 \([0,v)\) 永远不可能再被选了,因为想要将某个数从 \(S\) 中清除必须选择一个更小的不在 \(S\) 里的数,而作为前缀连续段这是不可能的。这就启发我们比较两个 \(S\) 的字典序:对于最小的 \(v\),满足 \([v\in S_1]\neq [v\in S_2]\),不妨设 \(v\notin S_2\);当 \(S_{1/2}\) 作为儿子时,不妨设其他 \(S_i\) 都不包含 \(v\)(否则选 \(S_1\)\(u_0<v\),一定寄了,\(S_2\) 不劣),那么当选择 \(S_2\) 时我们有令 \(d_x=v\) 的权利,显然后续得到的新 \(S\) 优于选择 \(S_1\) 时的任意决策。

这就是说,\(S\) 作为二进制数,字典序越小越好,也就是 \(u\) 应当取合法的最大值。这样决策永远是唯一的,我们成功造出了一个贪心算法。时间复杂度 \(\mathrm O(n\log\log n)\)代码

进一步观察这个贪心,发现对不同的 \(L\) 仿佛就是将 \(S\) 们平移了一样,而我们要求的 \(L\) 正是最小的使得各 \(S\) 不渗透到负下标的偏移量。容易想到记录各子树的最小 \(L\) 以及对应的 \(S\),转移时按最大偏移量进行对齐,再根据需求增大偏移量即可。时间复杂度 \(\mathrm O(n)\)代码

posted @ 2023-05-25 23:18  ycx060617  阅读(276)  评论(0编辑  收藏  举报