#P2368. 第2题-频率搬移值分配
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 343
            Accepted: 137
            Difficulty: 6
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2023年8月30日-国内
                              
                      
          
 
- 
                        算法标签>DFS          
 
第2题-频率搬移值分配
题面描述
在无线通信设备中,超外差接收机通过将输入信号与本地产生的振荡波混频来变换频率。为了节省器件,设计了一种二又树型的混频器组,可以同时将信号搬移到不同的频率。给定一个完全二叉树的层数和每个叶子节点的目标频率值,我们需要计算树中每个节点的值,节点值由其所有叶子节点的最大值和最小值的平均值减去其所有父节点值的总和。最终以数组形式输出该二叉树的节点值。
思路: DFS
建立一个满二叉树,从下往上建树,每个节点存储当前最大值和最小值,叶子结点最大值和最小值一样,没个节点只需要考虑自己的左孩子和右孩子。由两个孩子来更新自身的最大值和最小值。从下往上建树后从上向下DFS,每层携带一个参数表示所有父亲的值的和。
题解
在无线通信设备中,超外差接收机的信号处理可以通过构建满二叉树来实现。这个树的每个节点存储当前子树的最大值和最小值,以便在后续的信号处理中快速计算频率的范围。具体步骤如下:
- 
树的构建:我们从下往上建立满二叉树,叶子节点直接使用给定的目标频率值。非叶子节点通过其左右孩子节点更新自身的最大值和最小值。具体而言,叶子节点的最大值和最小值相同,父节点的最大值为其两个孩子的最大值,最小值为其两个孩子的最小值。
 - 
DFS遍历:构建完树后,使用深度优先搜索(DFS)从上到下遍历树。每次遍历时,携带一个参数表示所有父节点的值的和,这样可以在计算当前节点的最终值时,减去父节点的和。
 - 
输出结果:最终,输出每个节点的值,表示它在树中的状态。
 
代码
C++
#include <bits/stdc++.h>
using namespace std;
using ll = long long; // 定义长整型别名
using pii = pair<int, int>; // 定义一个整数对,用于存储最大值和最小值
int main() {
    ios::sync_with_stdio(0); // 加速输入输出
    cin.tie(0);
    
    int n;
    cin >> n; // 读取叶子节点的数量
    vector<int> a(n + 1); // 用于存储叶子节点的目标频率值
    for (int i = 1; i <= n; i++) {
        cin >> a[i]; // 读取每个叶子节点的目标频率值
    }
    
    vector<ll> seg(n * 2); // 用于存储树节点的值,大小为2n
    
    // 建树函数,返回当前节点的最小值和最大值
    function<pii(int, int, int)> build = [&](int x, int l, int r) -> pii { 
        if (l == r) { // 如果到达叶子节点
            seg[x] = a[l]; // 叶子节点的值为目标频率值
            return {a[l], a[l]}; // 返回最小值和最大值(相同)
        } else {
            int mid = l + (r - l) / 2; // 计算中间位置
            pii a = build(x * 2, l, mid); // 递归建造左子树
            pii b = build(x * 2 + 1, mid + 1, r); // 递归建造右子树
            int mi = min(a.first, b.first); // 当前节点的最小值
            int mx = max(a.second, b.second); // 当前节点的最大值
            seg[x] = (mx + mi) / 2; // 当前节点的值为最大值和最小值的平均值
            return {mi, mx}; // 返回当前节点的最小值和最大值
        }
    };
    build(1, 1, n); // 从根节点开始建树
    // DFS遍历函数,x为当前节点,p为父节点值的和
    function<void(int, ll)> dfs = [&](int x, ll p) -> void { 
        if (x >= n * 2) return; // 超出节点范围,结束递归
        seg[x] -= p; // 当前节点值减去父节点的和
        // 递归遍历左右子树,将当前节点值和传递给孩子节点
        dfs(x * 2, p + seg[x]); 
        dfs(x * 2 + 1, p + seg[x]);
    };
    dfs(1, 0); // 从根节点开始DFS,初始父节点值为0
    // 输出结果
    for (int i = 1; i < n * 2; i++) {
        cout << seg[i] << ' '; // 输出每个节点的值
    }
    cout << endl; // 换行
}
java
import java.util.Scanner;
public class Main {
    static int n;
    static int[] a;
    static long[] seg;
    static class Pair {
        int first, second;
        Pair(int f, int s) {
            first = f;
            second = s;
        }
    }
    static Pair build(int x, int l, int r) {
        if (l == r) { // 叶子节点的最大值和最小值一样
            seg[x] = a[l];
            return new Pair(a[l], a[l]);
        } else {
            int mid = l + (r - l) / 2;
            Pair a = build(x * 2, l, mid); // 左孩子建树
            Pair b = build(x * 2 + 1, mid + 1, r); // 右孩子建树
            int mi = Math.min(a.first, b.first); // 更新当前节点的孩子最大值
            int mx = Math.max(a.second, b.second); // 更新当前节点的孩子最小值
            seg[x] = (mx + mi) / 2; // 当前节点权值
            return new Pair(mi, mx);
        }
    }
    static void dfs(int x, long p) { // 从上向下遍历,将父节点的和作为参数向下传递
        if (x >= n * 2) return;
        seg[x] -= p;
        dfs(x * 2, p + seg[x]);
        dfs(x * 2 + 1, p + seg[x]);
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        a = new int[n + 1];
        seg = new long[n * 2 + 1];
        for (int i = 1; i <= n; i++) {
            a[i] = scanner.nextInt();
        }
        build(1, 1, n);
        dfs(1, 0);
        for (int i = 1; i < n * 2; i++) {
            System.out.print(seg[i] + " ");
        }
        System.out.println();
    }
}
python
import sys
n = int(input())
a = [0] + list(map(int, input().split()))
seg = [0] * (n * 2)
def build(x, l, r):
    if l == r: # 叶子节点的最大值和最小值一样
        seg[x] = a[l]
        return (a[l], a[l])
    else:
        mid = l + (r - l) // 2
        a_l, a_r = build(x * 2, l, mid) # 左孩子建树
        b_l, b_r = build(x * 2 + 1, mid + 1, r) # 右孩子建树
        mi = min(a_l, b_l) # 更新当前节点的孩子最大值
        mx = max(a_r, b_r) # 更新当前节点的孩子最小值
        seg[x] = (mx + mi) // 2 # 当前节点权值
        return (mi, mx)
build(1, 1, n)
def dfs(x, p): # 从上向下遍历,将父节点的和作为参数向下传递
    if x >= n * 2:
        return
    seg[x] -= p
    dfs(x * 2, p + seg[x])
    dfs(x * 2 + 1, p + seg[x])
dfs(1, 0)
for i in range(1, n * 2):
    print(seg[i], end=' ')
print()
        题目内容
在无线通信设备中通常使用超外差接收机,超外差接收机是利用本地产生的振荡波与输入信号混频,将输入信号频率变换为某个预先确定的频率的方法。也就是说,信号通过一个混频器后,频率就会搬移一个数值。在项目中由于要节省器件,混频器需要尽可能的共享,我们设计了二又树型的混频器组,可以同时把信号搬移到不同的频率上。
二又树为完全二叉树。我们给定二叉树的层数和从根节点开始到每个子节点的频率搬移总和输出二又树。
规则: 节点的值为它的所有叶子节点的目标频率值最大值和最小值的平均值 (非整数向下取整)减去 它所有父节点的总和。
| A | 频率范围10~70, 则值是(10+70)/2=40 | ||||||
|---|---|---|---|---|---|---|---|
| B | C | 频率范围30~70,则值是(30+70)/2-40=10 | |||||
| D | E | F | G | 频率范围70,则值是70-10-40=20 | |||
| 10 | 20 | 30 | 70 | 目标帧率 | |||
满足:
- A+B+D=10
 - A+B+E=20
 - A+C+F=30
 - A+C+G=70
 
输入描述
- 叶子节点的数目 (必定是 2n),1≤叶子节点的数目≤4096
 - 每个叶子节点的目标频率值,二叉树的数组形式表示,把二叉树的结点依次自上而下,自左至右储存到数组中,0≤目标频率值≤1000000
 
输出描述
以数组形式的二叉树表示
样例
输入
4
18 24 2 3
输出
13 8 -11 -3 3 0 1
解释
第0层:所有叶子节点最大最小值的平均值为(2+24)/2=13所有父节点值为0,最终为 13−0=13
第1层左节点:所有叶子节点 最大最小值的平均值为(18+24)/2=21 所有父节点值为13,最终为21−13=8
第1层右节点:所有叶子节点 最大最小值的平均值为(2+3)/2=2所有父节点值为13,最终为2−13=−11
第2层第1个节点:所有叶子节点 最大最小值的平均值为18/1=18所有父节点值为13+8=21,最终为18−21=−3
第2层第2个节点: 所有叶子节点 最大最小值的平均值为24/1=24 所有父节点值为13+8=21,最终为24−21=3
第2层第3个节点: 所有叶子节点 最大最小值的平均值为2/1=2 所有父节点值为13+(−11)=2,最终为2−2=0
第2层第4个节点: 所有叶子节点 最大最小值的平均值为3/1=3 所有父节点值为13+(−11)=2,最终为3−2=1
| 13 | 频率范围2~24.则值是(2+24)/2=13 | ||||||
|---|---|---|---|---|---|---|---|
| 8 | -11 | 频率范围2-4,则值是(2+4)/2-13=-10 | |||||
| -3 | 3 | 0 | 1 | 频率范围4,则值是4-(-10)-13=1 | |||
| 18 | 24 | 2 | 3 | 目标帧率 | |||