满二叉树等长路径

满二叉树等长路径

给定一个深度为 $n$ 的满二叉树,其 $2^{n+1}−1$ 个顶点的编号为 $1 \sim 2^{n+1}−1$。

树的根节点为 $1$ 号节点,除根节点外,第 $i$ 号节点的父节点为第 $\left\lfloor \frac{i}{2} \right\rfloor$ 号节点。

例如,当 $n=3$ 时,二叉树如下所示:

 

树中每条边的长度已知,由此可以得到根节点到 $2^{n}$ 个叶节点的距离。

为了使得根节点到每个叶节点的距离都相等,我们可以进行任意次增边操作。

每次操作可以选择任意一条边,将其增加任意正整数长度。

我们希望在达成目的的同时,所有边的总增加长度尽可能小。

请你计算并输出总增加长度的最小可能值。

输入格式

第一行包含整数 $n$。

第二行包含 $2^{n+1}−2$ 个整数 $a_{2},a_{3},…,a_{2^{n+1}−1}$,其中 $a_{i}$ 表示第 $i$ 号节点与第 $\left\lfloor \frac{i}{2} \right\rfloor$ 号节点之间的边的长度。

输出格式

一个整数,表示总增加长度的最小可能值。

数据范围

前三个测试点满足 $1 \leq n \leq 2$。
所有测试点满足 $1 \leq n \leq 10,1 \leq a_{i} \leq 100$。

输入样例:

2
1 2 3 4 5 6

输出样例:

5

 

解题思路

  这题在做的时候猜对了做法,贪心题,难得。

  假设根节点到叶子结点的距离都相同,对于上面的左子树,每一个叶子结点到左儿子的距离是相同的。如果不相同,意味着存在两个叶子结点到左儿子的距离不同,即这两个叶子结点到根节点的距离不相等,就与根节点到叶子结点的距离都相同矛盾了。右子树同理。

  现在假设左子树的每个叶子结点到根节点的距离为$x$,右子树的每个叶子结点到根节点的距离为$y$。现在我们希望根节点到左右子树的叶子结点的距离都相同,假设最终的距离为$d$,由于只能够增加距离,因此有$d \geq max \left\{ {x, y} \right\}$。那么左子树的每一个叶子结点到根节点的距离就要增加$d - x$,右子树的每一个叶子结点到根节点的距离就要增加$d - y$。

  对于左子树,我们看一下$d - x$增加在哪个地方。如果增加在根节点到左儿子的这条边上,那么只用增加一次。如果在第二层增加,那么就要增加$2 \times \left( {d - x} \right)$次(左儿子的两条边各一次),如果在第三层增加,就要增加$2^{2} \times \left( {d - x} \right)$次,以此类推,所以为了增加的数量尽可能少,我们应该在根节点到左儿子的这条边上增加。右子树同理。

  所以增加的总代价为$d - x + d - y = 2 \cdot d - \left( {x + y} \right)$,要让代价最小,那么$d$就应该最小,即$d = max \left\{ {x, y} \right\}$,因此最小代价就为$\left| {x - y} \right|$。

  可以发现,$x$是每个左子树的叶子节点到根节点的最小距离,$y$是每个右子树的叶子节点到根节点的最小距离。对于$\left| {x - y} \right|$,如果$x$稍微增大一些,那么这个绝对值就会减少。假设增加$c$,可这意味着从第二层开始,至少要增加$2 \times c$,这样代价反而会增加。虽然$x$增加$c$后会对当前这层的代价减少,但总的代价会增加,因此每次都应该取到根节点的最小距离。

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = (1 << 11) + 10;
 7 
 8 int n, ans;
 9 int a[N];
10 
11 // dfs返回叶子节点到u的最小距离
12 int dfs(int u) {
13     if (u << 1 > (1 << n + 1) - 1) return 0;    // 不存在左儿子,什么是叶子节点
14     
15     int l = dfs(u << 1) + a[u << 1];        // 求左子树的叶子结点到u的距离
16     int r = dfs(u << 1 | 1) + a[u << 1 | 1];// 求右子树的叶子结点到u的距离
17     ans += abs(l - r);
18     
19     return max(l, r);   // l和r的最大距离就是u到叶子节点的最小距离
20 }
21 
22 int main() {
23     scanf("%d", &n);
24     
25     int m = (1 << n + 1) - 1;
26     for (int i = 2; i <= m; i++) {
27         scanf("%d", a + i);
28     }
29     
30     dfs(1);
31     printf("%d", ans);
32     
33     return 0;
34 }

 

参考资料

  AcWing 4312. 出现次数(AcWing杯 - 周赛):https://www.acwing.com/video/3729/

posted @ 2022-03-13 12:11  onlyblues  阅读(65)  评论(0编辑  收藏  举报
Web Analytics