https://www.acmicpc.net/problem/13325
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int height;
static int answer;
static int[] weights;
static void input() {
Reader scanner = new Reader();
height = scanner.nextInt();
int totalNodeCount = (int) Math.pow(2, height + 1) - 1;
weights = new int[totalNodeCount + 1];
for (int idx = 2; idx <= totalNodeCount; idx++) {
weights[idx] = scanner.nextInt();
}
}
/*
* 이때 후위 탐색을 이용하여 가중치를 증가시킨다
* - 우선 DFS를 통해 리프 노드까지 이동하고 리프 노드에 도달하면 리프 노드의 가중치를 반환한다
* - 이때, 정답을 나타내는 변수에 리프 노드 가중치를 더한 후 반환한다 (모든 가중치를 더해야하므로)
* - 이렇게 한 노드의 왼쪽, 오른쪽 자식의 가중치를 알게 되면 두 가중치 중 더 높은 가중치와 현재 노드의 가중치를 합하여 반환한다
* - 결국, 루트 노드부터 리프 노드까지의 모든 경로 중 가장 가중치 합이 높은 경로의 가중치 합에 맞춰서 가중치를 증가시켜야 한다
* - 그러므로 아래에서부터 가중치 합을 더해나가며 더 높은 가중치의 합들을 위로 올리면서 모든 경로의 가중치의 합을 일치하도록 증가시킨다
* - 이때, 아래에서부터 올라온 가중치의 합이 왼쪽 서브 트리와 오른쪽 서브 트리에서 올라올텐데
* 두 합 중 더 작은 합에 두 합의 차이만큼 증가시켜줘야 하기 때문에
* 정답을 나타내는 변수에 현재 노드의 가중치와 두 합의 차이만큼을 더해준다
* - 더 합이 작은 곳에 차이만큼 증가시켜줬으니 이 차이 역시 정답에 더해줘야 한다
* - 이렇게 루트 노드까지 올라가며 총 노드의 가중치의 합을 구한다
*/
static void solution() {
calculateWeightSum(1, 0);
System.out.println(answer);
}
static int calculateWeightSum(int curIdx, int curHeight) {
if (curHeight == height) {
answer += weights[curIdx];
return weights[curIdx];
}
int left = calculateWeightSum(curIdx * 2, curHeight + 1);
int right = calculateWeightSum(curIdx * 2 + 1, curHeight + 1);
answer += (weights[curIdx] + Math.abs(right - left));
return weights[curIdx] + Math.max(left, right);
}
public static void main(String[] args) {
input();
solution();
}
static class Reader {
BufferedReader br;
StringTokenizer st;
public Reader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
}
}