满二叉树等长路径

满二叉树等长路径

给定一个深度为 n 的满二叉树,其 2n+11 个顶点的编号为 12n+11

树的根节点为 1 号节点,除根节点外,第 i 号节点的父节点为第 i2 号节点。

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

 

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

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

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

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

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

输入格式

第一行包含整数 n

第二行包含 2n+12 个整数 a2,a3,,a2n+11,其中 ai 表示第 i 号节点与第 i2 号节点之间的边的长度。

输出格式

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

数据范围

前三个测试点满足 1n2
所有测试点满足 1n101ai100

输入样例:

2
1 2 3 4 5 6

输出样例:

5

 

解题思路

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

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

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

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

  所以增加的总代价为dx+dy=2d(x+y),要让代价最小,那么d就应该最小,即d=max{x,y},因此最小代价就为|xy|

  可以发现,x是每个左子树的叶子节点到根节点的最小距离,y是每个右子树的叶子节点到根节点的最小距离。对于|xy|,如果x稍微增大一些,那么这个绝对值就会减少。假设增加c,可这意味着从第二层开始,至少要增加2×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 @   onlyblues  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2021-03-13 图解带头节点的单链表的反转操作
Web Analytics
点击右上角即可分享
微信分享提示