在线评测链接
题目内容
在无线通信设备中通常使用超外差接收机,超外差接收机是利用本地产生的振荡波与输入信号混频,将输入信号频率变换为某个预先确定的频率的方法。也就是说,信号通过一个混频器后,频率就会搬移一个数值。在项目中由于要节省器件,混频器需要尽可能的共享,我们设计了二又树型的混频器组,可以同时把信号搬移到不同的频率上。
二又树为完全二叉树。我们给定二叉树的层数和从根节点开始到每个子节点的频率搬移总和输出二又树。
规则: 节点的值为它的所有叶子节点的目标频率值最大值和最小值的平均值 (非整数向下取整)减去 它所有父节点的总和。
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+D=10 A+B+D=10
- A + B + E = 20 A+B+E=20 A+B+E=20
- A + C + F = 30 A+C+F=30 A+C+F=30
- A + C + G = 70 A+C+G=70 A+C+G=70
输入描述
- 叶子节点的数目 (必定是 2 n 2^n 2n), 1 ≤ 叶子节点的数目 ≤ 4096 1 \leq 叶子节点的数目 \leq 4096 1≤叶子节点的数目≤4096
- 每个叶子节点的目标频率值,二叉树的数组形式表示,把二叉树的结点依次自上而下,自左至右储存到数组中, 0 ≤ 目标频率值 ≤ 1000000 0 \leq 目标频率值 \leq 1000000 0≤目标频率值≤1000000
输出描述
以数组形式的二叉树表示
样例
输入
4
18 24 2 3
输出
13 8 -11 -3 3 0 1
解释
第 0 0 0层:所有叶子节点最大最小值的平均值为$(2+24)/2=13 $所有父节点值为 0 0 0,最终为 13 − 0 = 13 13-0=13 13−0=13
第 1 1 1层左节点:所有叶子节点 最大最小值的平均值为 ( 18 + 24 ) / 2 = 21 (18+24)/2=21 (18+24)/2=21 所有父节点值为13,最终为 21 − 13 = 8 21-13=8 21−13=8
第 1 1 1层右节点:所有叶子节点 最大最小值的平均值为$(2+3)/2=2 $所有父节点值为 13 13 13,最终为 2 − 13 = − 11 2-13=-11 2−13=−11
第 2 2 2层第 1 1 1个节点:所有叶子节点 最大最小值的平均值为$18/1=18 $所有父节点值为 13 + 8 = 21 13+8 =21 13+8=21,最终为 18 − 21 = − 3 18-21=-3 18−21=−3
第 2 2 2层第 2 2 2个节点: 所有叶子节点 最大最小值的平均值为 24 / 1 = 24 24/1=24 24/1=24 所有父节点值为 13 + 8 = 21 13+8 =21 13+8=21,最终为 24 − 21 = 3 24 - 21=3 24−21=3
第 2 2 2层第 3 3 3个节点: 所有叶子节点 最大最小值的平均值为 2 / 1 = 2 2/1=2 2/1=2 所有父节点值为 13 + ( − 11 ) 13+(-11) 13+(−11)= 2 2 2,最终为 2 − 2 = 0 2-2 =0 2−2=0
第 2 2 2层第 4 4 4个节点: 所有叶子节点 最大最小值的平均值为 3 / 1 = 3 3/1=3 3/1=3 所有父节点值为 13 + ( − 11 ) = 2 13+(-11)=2 13+(−11)=2,最终为 3 − 2 = 1 3-2 = 1 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 | 目标帧率 |
思路: 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);
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; // 当前节点权值
//out2(mx, mi);
return {mi, mx};
}
};
build(1, 1, n);
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);
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()