#include <bits/stdc++.h>
#define _overload3(_1,_2,_3,name,...)name
#define _rep(i,n)repi(i,0,n)
#define repi(i,a,b)for(int i=int(a),i##_len=(b);i<i##_len;++i)
#define MSVC_UNKO(x)x
#define rep(...)MSVC_UNKO(_overload3(__VA_ARGS__,repi,_rep,_rep)(__VA_ARGS__))
#define all(c)c.begin(),c.end()
#define write(x)cout<<(x)<<'\n'
using namespace std; using ll = long long; template<class T>using vv = vector<vector<T>>;
template<class T>auto vvec(int n, int m, T v) { return vv<T>(n, vector<T>(m, v)); }
constexpr int INF = 1 << 29, MOD = int(1e9) + 7; constexpr ll LINF = 1LL << 60;
struct aaa { aaa() { cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(10); }; }aaaa;

template<typename T, class F, const T & I>
struct SegmentTree {
    const F op;
    int n; vector<T> dat;
    SegmentTree() : op() {}
    SegmentTree(F f) : op(f) {}
    T operator [](int i) const { return dat[n + i]; }
    void build(const vector<T>& v) {
        int n_ = v.size(); init(n_); for (int i = 0; i < n_; ++i) dat[n + i] = v[i];
        for (int i = n - 1; i; --i) dat[i] = op(dat[i * 2], dat[i * 2 + 1]);
    }
    void init(int n_) { n = 1; while (n < n_) n *= 2; dat.assign(n * 2, I); }
    template<class T_ = T, class SA = enable_if_t<is_same<remove_reference_t<T_>, T>::value>>
    void update(int k, T_&& v) { dat[k += n] = v; while (k /= 2) dat[k] = op(dat[k * 2], dat[k * 2 + 1]); }
    T query(int a, int b) const {
        T vl = I, vr = I;
        for (int l = a + n, r = b + n; l < r; l /= 2, r /= 2) { if (l & 1) vl = op(vl, dat[l++]); if (r & 1) vr = op(dat[--r], vr); }
        return op(vl, vr);
    }
    template<class C> int find(int a, int b, C&& check) const { return find(a, b, check, 1, 0, n); }
private:
    template<class C> int find(int a, int b, C&& check, int k, int l, int r) const {
        if (!check(dat[k]) || r <= a || b <= l) return -1; else if (k >= n) return k - n;
        int m = (l + r) / 2; int vl = find(a, b, check, k * 2, l, m); if (~vl) return vl;
        else return find(a, b, check, k * 2 + 1, m, r);
    }
};

template<typename T> struct min_of {
    template<typename T_L = T, typename T_R = T>
    constexpr T operator ()(T_L&& lhs, T_R&& rhs) const { return min(lhs, rhs); }
};
extern constexpr int identity = INT32_MAX;

using ST = SegmentTree<int, min_of<int>, identity>;

int main() {
    int N;
    cin >> N;
    vector<int> P(N);
    rep(i, N) cin >> P[i], P[i]--;

    vector<int> idx(N);
    rep(i, N) idx[P[i]] = i;

    ST st[2];
    {
        vector<int> v;
        v.assign(N, identity);
        rep(i, N / 2) v[2 * i] = P[2 * i];
        st[0].build(v);
        v.assign(N, identity);
        rep(i, N / 2) v[2 * i + 1] = P[2 * i + 1];
        st[1].build(v);
    }

    vector<pair<int, int>> ranges(N);
    priority_queue<int, vector<int>, greater<int>> pq;
    {
        auto p_begin = st[0].dat[1];
        ranges[p_begin] = { 0, N };
        pq.push(p_begin);
    }

    vector<int> Q(N);
    rep(i, N / 2) {
        int p = pq.top();
        int o = idx[p] % 2;
        int q = st[1 - o].query(idx[p] + 1, ranges[p].second);
        pq.pop();
        Q[2 * i] = p + 1;
        Q[2 * i + 1] = q + 1;

        if (idx[p] != ranges[p].first) {
            int r = st[o].query(ranges[p].first, idx[p]);
            ranges[r] = { ranges[p].first, idx[p] };
            pq.push(r);
        }
        if (idx[p] + 1 != idx[q]) {
            int r = st[1 - o].query(idx[p] + 1, idx[q]);
            ranges[r] = { idx[p] + 1, idx[q] };
            pq.push(r);
        }
        if (idx[q] + 1 != ranges[p].second) {
            int r = st[o].query(idx[q] + 1, ranges[p].second);
            ranges[r] = { idx[q] + 1, ranges[p].second };
            pq.push(r);
        }
    }

    rep(i, N) cout << Q[i] << (!--N ? "\n" : " ");
}


Measured memory_bytes: 9968