CF的题解:D. 双倍经验

题目链接:

题目大意:

给出一棵 $n$ 个节点的树,每个节点有一个点权 $a_i$,每次可以选择一条边,将这条边的两端节点的点权加倍。求使得所有点权都相等的最小操作次数。

思路:

首先我们可以发现,如果树的所有节点的点权都相等,那么这棵树的根节点的点权一定是所有点权的平均值。

我们可以考虑从叶子节点开始,一步步向上更新点权。对于每个节点,如果它的子节点的点权都已经相等了,那么我们就可以将这个节点的点权更新为它所有子节点的点权之和,再除以子节点的个数,这样就可以保证它的点权和子节点的点权相等。

但是这样做有一个问题,就是如果子节点的点权已经比父节点的点权大了,那么更新之后父节点的点权就会变大,这样可能会影响到兄弟节点的更新。

为了避免这种情况,我们可以在更新每个节点的点权之前,先判断一下它的子节点的点权是否都小于等于它的点权。如果子节点的点权都小于等于它的点权,那么我们就可以直接更新它的点权。

如果子节点的点权有大于它的点权的,那么我们就需要将这个节点的点权更新为它所有子节点的点权之和,再除以子节点的个数,但是我们不能直接更新它的点权,而是需要将这个节点的点权更新成所有子节点的点权中的最大值。

这样做的正确性可以通过数学归纳法证明。假设我们已经将所有子节点的点权更新成相等的值,那么对于父节点,如果它的所有子节点的点权都小于等于它的点权,那么它的点权也会被更新成相等的值;如果它的某个子节点的点权大于它的点权,那么这个子节点的点权会被更新为所有子节点的点权中的最大值,因此父节点的点权也会被更新为最大值,这样就可以保证父节点的点权不会比它的兄弟节点的点权大。

代码:

标签:cf有代码