/*
* Problem :: 9934 / 완전 이진 트리
*
* Kind :: Data Structure
*
* Insight
* - 도시를 방문한 순서 = 중위 순회
* + 레벨 i의 루트노드 = RN_i
* 레벨 i의 왼쪽 서브트리 = LST_i
* 레벨 i의 오른쪽 서브트리 = RST_i
* 레벨 i의 오른쪽 서브트리의 왼쪽 서브트리 = RLST_i
* 레벨 i의 오른쪽 서브트리의 왼쪽 서브트리의 왼쪽 서브트리 = RLLST_i
* # LST_1 - RN_1 - RST_1
* LST_1 => LLST_2 - RN_2 - LRST_2
* RST_1 => RLST_2 - RN_2 - RRST_2
* -> (LLST_2 - RN_2 - LRST_2) - RN_1 - (RLST_2 - RN_2 - RRST_2)
*
* # 1
* 2 3 => 2 - 1 - 3
*
* # 3
* 6 2
* 1 4 5 7 => 6 - 3 - 2 => (1 - 6 - 4) - 3 - (5 - 2 - 7)
* 1 4 5 7
*
* -> 서브트리를 방문할 때마다 레벨이 하나씩 증가한다
* 완전 이진 트리이므로 중위 순회한 빌딩의 개수는 항상 홀수이다
* 빌딩을 중위 순회한 결과에서 가운데 빌딩의 번호가 루트노드이다
* 루트노드를 기준으로 왼편에 있는 중위 순회한 결과가
* 왼쪽 서브트리를 중위 순회한 결과이다
* 루트노드를 기준으로 오른편에 있는 중위 순회한 결과가
* 오른쪽 서브트리를 중위 순회한 결과이다
* => 재귀적으로 방문해주자!
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
#define endl '\n'
// Set up : Global Variables
int K;
int A[1023+1];
vector<int> L[10+1];
// Set up : Functions Declaration
void f(int s, int e, int lev);
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
cin >> K;
int S = pow(2,K)-1; /* 빌딩의 개수 */
for (int i=1; i<=S; i++)
cin >> A[i];
// Process
f(1, S, 1);
// Control : Output
for (int i=1; i<=K; i++) {
for (int n : L[i]) {
cout << n << ' ';
} cout << endl;
}
}
// Helper Functions
void f(int s, int e, int lev)
/* s = 중위 순회 결과의 시작 인덱스
* e = 중위 순회 결과의 종료 인덱스
* 현재 (서브)트리의 중위 순회 결과 = A[s], A[s+1], ..., A[e-1], A[e]
* 현재 (서브)트리의 레벨 = lev */
{
int m = (s+e) / 2; /* 중위 순회 결과의 가운데 인덱스 */
L[lev].push_back(A[m]); /* L[i] = 레벨 i인 빌딩의 번호들 */
if (s == e) return;
f(s, m-1, lev+1); /* 왼쪽 서브트리 */
f(m+1, e, lev+1); /* 오른쪽 서브트리 */
}