#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
  
#define mp       make_pair
#define pb       push_back
#define all(x)   (x).begin(),(x).end()
#define rep(i,n) for(int i=0;i<(n);i++)
  
using namespace std;
  
typedef    long long          ll;
typedef    unsigned long long ull;
typedef    vector<bool>       vb;
typedef    vector<int>        vi;
typedef    vector<vb>         vvb;
typedef    vector<vi>         vvi;
typedef    pair<int,int>      pii;
  
const double EPS = 1e-9;

#include <climits>
template<class T = int, int INF = INT_MAX>
struct SegmentTree {
    vector<T> node;
    vector<int> node_i;
    int n;
    explicit SegmentTree(vector<T> a) {
        int n_ = a.size();
        n = 1;
        while(n < n_) n <<= 1;
        node.resize(2 * n - 1, INF);
        node_i.resize(2 * n - 1, INF);
        for(int i = 0; i < n_; i++) {
            node[n - 1 + i] = a[i];
            node_i[n - 1 + i] = i;
        }
        for(int i = n - 2; i >= 0; i--) {
            node_i[i] = node[2 * i + 1] < node[2 * i + 2] ? node_i[2 * i + 1] : node_i[2 * i + 2];
            node[i] = min(node[2 * i + 1], node[2 * i + 2]);
        }
    }
    explicit SegmentTree(int n_): SegmentTree(vector<T>(n_, INF)) {}
    void update(int i, T x) {
        i = n - 1 + i;
        node[i] = x;
        while(i > 0) {
            i = (i - 1) / 2;
            node_i[i] = node[2 * i + 1] < node[2 * i + 2] ? node_i[2 * i + 1] : node_i[2 * i + 2];
            node[i] = min(node[i * 2 + 1], node[i * 2 + 2]);
        }
    }
    pair<int, T> find(int a, int b, int k = 0, int l = 0, int r = 0) {
        if (l == 0 && r == 0) r = n;
        if (r <= a || b <= l) return make_pair(-1, INF);
        if (a <= l && r <= b) return make_pair(node_i[k], node[k]);

        pair<int, T> vl = find(a, b, 2 * k + 1, l, (l + r) / 2);
        pair<int, T> vr = find(a, b, 2 * k + 2, (l + r) / 2, r);
        return vl.second < vr.second ? vl : vr;
    }
};

struct segment {
    int v;
    int l, r;
    bool operator>(const segment &rhs) const {
        return v > rhs.v;
    }
};

int main() {
    int N;
    cin >> N;
    vector<int> P;
    for (int i = 0; i < N; i++) {
        int p;
        cin >> p;
        P.push_back(p);
    }
    SegmentTree<> seg1(N);
    SegmentTree<> seg2(N);
    for(int i = 0; i < N; i++) {
        if (i % 2 == 0) seg1.update(i, P[i]);
        else seg2.update(i, P[i]);
    }

    priority_queue<segment, vector<segment>, greater<segment> > Q;
    int l = 0;
    int r = N;
    Q.push({0, l, r});
    vector<int> ans;
    for(int q = 0; q < N / 2; q++) {
        segment s = Q.top(); Q.pop();
        int l = s.l, r = s.r;
        pair<int,int> mi1, mi2;
        if (l % 2 == 0) {
            mi1 = seg1.find(l, r);
            mi2 = seg2.find(mi1.first + 1, r);
        } else {
            mi1 = seg2.find(l, r);
            mi2 = seg1.find(mi1.first + 1, r);
        }
        ans.push_back(mi1.second);
        ans.push_back(mi2.second);

        pair<int,int> ml, mc, mr;
        if (l % 2 == 0) {
            ml = seg1.find(l, mi1.first);
            mc = seg2.find(mi1.first + 1, mi2.first);
            mr = seg1.find(mi2.first + 1, r);
        } else {
            ml = seg2.find(l, mi1.first);
            mc = seg1.find(mi1.first + 1, mi2.first);
            mr = seg2.find(mi2.first + 1, r);
        }

        if (l != mi1.first) {
            Q.push({ml.second, l, mi1.first});
        }
        if (mi1.first + 1 != mi2.first) {
            Q.push({mc.second, mi1.first + 1, mi2.first});
        }
        if (mi2.first + 1 != r) {
            Q.push({mr.second, mi2.first + 1, r});
        }
    }

    for (int i = 0; i < ans.size(); i++) {
        cout << ans[i] << " ";
    }
    cout << endl;
    return 0;
}

Measured memory_bytes: 12784