#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

#define MOD 1000000007
#define INF 1000000000
#define MAX_N 200005

int n;                      // 葉の数。2 のべき乗
pair<int, int> even[MAX_N * 2 - 1];    // 偶数番目の要素のセグメント木 (位置, 値)
pair<int, int> odd[MAX_N * 2 - 1];     // 奇数番目の要素のセグメント木 (位置, 値)
// セグメント木での Range Minimum Query (RMQ) の実装
// 区間[i, j] に含まれる最小値の取得と、値の更新
// 初期化
void init() {
    REP(i, 2*n-1){
        even[i].first = i;
        even[i].second = INF;
        odd[i].first = i;
        odd[i].first = INF;
    }
}
// 値の更新 O(log n)
// i 番目の値 (0-indexed) を x に変更
void update(bool isEven, int i, pair<int, int> x) {
    // 葉の番号
    i += n - 1;
    if(isEven) {
        even[i] = x;
        //printf("update even[%d] to (%d, %d)\n", i, even[i].first, even[i].second);
    }
    else {
        odd[i] = x;
        //printf("update odd[%d] to (%d, %d)\n", i, odd[i].first, odd[i].second);
    }
    // 登りながら更新
    while(i>0) {
        i = (i-1)/2;
        if(isEven) {
            if(even[i*2+1].second < even[i*2+2].second) { even[i] = even[i*2+1]; }
            else { even[i] = even[i*2+2]; }
        }
        else {
            if(odd[i*2+1].second < odd[i*2+2].second) { odd[i] = odd[i*2+1]; }
            else { odd[i] = odd[i*2+2]; }
        }
    }
}
// 最小値の取得 O(log n)
// [a, b) の最小値、 l, r にはノード k に対応づく区間を与える
// 一番初めは query_impl(a, b, 0, 0, n) のように呼ぶ
pair<int, int> query_impl(bool isEven, int a, int b, int k, int l, int r) {
    if(r <= a || b <= l){ return make_pair(INF, INF); } // 交差しない？
    if(a <= l && r <= b){
        if(isEven) { return even[k]; }
        else { return odd[k]; }
    }  // 完全に含む？
    else {
        pair<int, int> vl = query_impl(isEven, a, b, k * 2 + 1, l, (l + r) / 2);    // 左の子を見る
        pair<int, int> vr = query_impl(isEven, a, b, k * 2 + 2, (l + r) / 2, r);    // 右の子を見る
        //printf("  vl.second %d vr.second %d\n", vl.second, vr.second);
        if(vl.second < vr.second) { return vl; }
        else { return vr; }
    }
}
pair<int, int> query(bool isEven, int a, int b) {
    return query_impl(isEven, a, b, 0, 0, n);
}

int ans[MAX_N * 4];
int N;

// 2 のべき乗かどうか
int isPow(int num) {
    int res = 2;
    while(res < num) {
        res *= 2;
    }
    if(res == num) { return 0; }
    else { return res - num; }
}

int main()
{
    ZERO(ans);
    cin >> N;
    n = N / 2;
    int ret = isPow(n);
    if(ret != 0) { n += ret; }
    // セグメント木の構築
    init();
    REP(i, N) {
        int tmp;
        //scanf("%d", &tmp);
        cin >> tmp;
        bool isEven = (i % 2 == 0);
        //printf("add ind %d (%d, %d) to %s\n", i / 2, i, tmp, (isEven) ? "even" : "odd");
        update(isEven, i / 2, make_pair(i, tmp));
    }

    // 区間 (区間の最小値, 区間の範囲 [) )
    priority_queue< pair<int, pair<int, int> >,
        vector< pair<int, pair<int, int> > >,
        greater< pair<int, pair<int, int> > > > range;
    range.push(make_pair(query(true, 0, n).second, make_pair(0, N)));
    //printf("min: %d\n", query(true, 0, n).second);
    //printf("min: %d\n", query(false, 0, n).second);
    //REP(i, 2*n-1) {
    //    printf("%d ", even[i].second);
    //}
    //printf("\n");
    //printf("test: %d\n", query(true, 0, 2).second);

    int ans_ind = 0;
    while(ans_ind < N) {
        // 最小の値を持つ区間を取得
        pair< int, pair<int, int> > min_range = range.top();
        range.pop();
        bool isEven = (min_range.second.first % 2 == 0);    // 区間の始点は偶数か？
        // 確定した値を入れる
        pair<int, int> cand1, cand2;
        //printf("min_range.second (%d, %d)\n", min_range.second.first, min_range.second.second);
        cand1 = query(isEven, min_range.second.first / 2, min_range.second.second / 2);
        if(isEven) {
            // cand2 では奇数を見る
            cand2 = query(false, cand1.first / 2, min_range.second.second / 2);
        } else {
            // cand2 では偶数を見る
            cand2 = query(true, cand1.first / 2 + 1, min_range.second.second / 2 + 1);
        }
        //printf("get (%d, %d) (%d, %d)\n", cand1.first, cand1.second, cand2.first, cand2.second);
        ans[ans_ind] = cand1.second;
        ans_ind++;
        ans[ans_ind] = cand2.second;
        ans_ind++;
        if(ans_ind >= N) { break; }
        // 区間を 3 つに分割
        pair<int, int> range1 = make_pair(min_range.second.first, cand1.first);
        pair<int, int> range2 = make_pair(cand1.first + 1, cand2.first);
        pair<int, int> range3 = make_pair(cand2.first + 1, min_range.second.second);
        // 各区間を priority_queue に入れる
        if(range1.first != range1.second) {
            isEven = (range1.first % 2 == 0);
            pair<int, int> min_range1 = query(isEven, range1.first / 2, range1.second / 2);
            assert(min_range1.first >= range1.first);
            assert(min_range1.first <= range1.second);
            range.push(make_pair(min_range1.second, range1));
            //printf("1add %d [%d, %d)\n", min_range1, range1.first, range1.second);
        }
        if(range2.first != range2.second) {
            isEven = (range2.first % 2 == 0);
            int min_range2 = query(isEven, range2.first / 2, range2.second / 2).second;
            range.push(make_pair(min_range2, range2));
            //printf("2add %d [%d, %d)\n", min_range2, range2.first, range2.second);
        }
        if(range3.first != range3.second) {
            isEven = (range3.first % 2 == 0);
            int min_range3 = query(isEven, range3.first / 2, range3.second / 2).second;
            range.push(make_pair(min_range3, range3));
            //printf("3add %d [%d, %d)\n", min_range3, range3.first, range3.second);
        }
        //printf("\n");
    }
    //assert(range.size() == 0);
    REP(i, N) {
        printf("%d", ans[i]);
        if(i != N - 1) { printf(" "); }
    }
    printf("\n");
    return 0;
}


Measured memory_bytes: 10360