// IO library
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <ios>
#include <iostream>

// algorithm library
#include <algorithm>
#include <cmath>
#include <numeric>
#include <random>

// container library
#include <bitset>
#include <deque>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <tuple>
#include <vector>

using namespace std;

using ll = long long;
using ld = long double;

template <class T>
ostream& operator<<(ostream& os, vector<T> v) {
    os << "[";
    for (auto vv : v) os << vv << ",";
    return os << "]";
}

template <class T>
ostream& operator<<(ostream& os, set<T> v) {
    os << "[";
    for (auto vv : v) os << vv << ",";
    return os << "]";
}

template <class L, class R>
ostream& operator<<(ostream& os, pair<L, R> p) {
    return os << "(" << p.first << "," << p.second << ")";
}

template <class K, class T>
ostream& operator<<(ostream& os, map<K, T> v) {
    os << "[";
    for (auto vv : v) os << vv << ",";
    return os << "]";
}

const ll MOD = 1000000007;
// const ll MOD = 998244353;
// const int INF = 1 << 25;
// const ll INF = 1LL << 50;
// const ld PI = acos(-1);
// const ld EPS = 1e-10;
// mt19937 mt(ll(time(0)));

template <typename T>
inline T sq(T a) { return a * a; }

template <typename T>
inline T iceil(T n, T d) { return (n + d - 1) / d; }

template <typename T>
T gcd(T a, T b) {
    if (a < b) return gcd(b, a);
    return b == 0 ? a : gcd(b, a % b);
}

template <typename T, typename U>
T ipow(T b, U n) {
    if (n == 0) return 1;
    if (n == 1) return b;
    return n % 2 == 0 ? mypow(b * b, n / 2) : mypow(b, n - 1) * b;
}

template <typename T, typename U>
T mpow(T b, U n) {
    if (n == 0) return 1;
    if (n == 1) return b % MOD;
    return n % 2 == 0 ? mypow(b * b % MOD, n / 2) : mypow(b, n - 1) * b % MOD;
}

const int INF = 1 << 30;

template <class Type>
class Segtree {
public:
    explicit Segtree(int N) : length(1) {
        while (length < N) length *= 2;
        nodes.assign(length * 2, INF);
    }

    Type query(int ql, int qr, int nidx, int nl, int nr) {
        if (nr <= ql || qr <= nl) return INF;
        if (ql <= nl && nr <= qr) return nodes[nidx];
        Type lvalue = query(ql, qr, nidx * 2, nl, (nl + nr) / 2);
        Type rvalue = query(ql, qr, nidx * 2 + 1, (nl + nr) / 2, nr);
        return min(lvalue, rvalue);
    }

    // half-open interval [ql, qr)
    Type query(int ql, int qr) {
        return query(ql, qr, 1, 0, length);
    }

    void update(int idx, Type value) {
        int nidx = idx + length;
        nodes[nidx] = value;
        while (nidx > 0) {
            nidx /= 2;
            nodes[nidx] = min(nodes[nidx * 2], nodes[nidx * 2 + 1]);
        }
    }

    int length;
    vector<Type> nodes;
};

int main() {
    int N;
    cin >> N;

    vector<Segtree<int>> seg(2, Segtree<int>(N));
    int p[N], rev[N];
    for (int i = 0; i < N; ++i) {
        cin >> p[i];
        --p[i];
        seg[i % 2].update(i, p[i]);
        rev[p[i]] = i;
    }

    vector<int> ans;

    priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> segque;
    segque.push(make_pair(seg[0].query(0, N), make_pair(0, N)));

    while (!segque.empty()) {
        int mi, l, r;
        pair<int, int> p;
        tie(mi, p) = segque.top();
        tie(l, r) = p;
        segque.pop();

        ans.push_back(mi);
        int d1 = rev[mi];
        mi = seg[(l + 1) % 2].query(d1 + 1, r);
        ans.push_back(mi);
        int d2 = rev[mi];

        pair<int, int> segs[3] = {{l, d1}, {d1 + 1, d2}, {d2 + 1, r}};

        for (int i = 0; i < 3; ++i) {
            tie(l, r) = segs[i];
            if (l < r) segque.push(make_pair(seg[l % 2].query(l, r), make_pair(l, r)));
        }
    }

    for (int a : ans) cout << a + 1 << " ";
    cout << endl;
    return 0;
}


Measured memory_bytes: 9468