#include <bits/stdc++.h>
#define SORT(x) sort((x).begin(), (x).end())
#define ALL(x) (x).begin(), (x).end()
#define rep(i, n) for (ll i = 0; i < n; i++)
#define reps(i, m, n) for (ll i = m; i < n; i++)
#define repr(i, m, n) for (ll i = m; i >= n; i--)
#define de(x) cout << #x << "=" << x << endl;
template <class T> bool maxi(T &a, const T &b) {
    if (a < b) { a = b; return 1;} return 0;}
template <class T> bool mini(T &a, const T &b) {
    if (b < a) { a = b; return 1;} return 0;}
#define dame {cout<< "-1" <<"\n"; return;}
#define SP << " " <<
#define INF2 1000000000000000037
#define INF  1000000007
#define MOD  1000000007
using namespace std;
using ll = long long;
using ld = long double;
using P  = pair<ll,ll>;
//--GLOBAL---------------------------------
template <class Mono = ll>
struct SegTree{
    using FuncMonoMono = function<Mono(Mono,Mono)>;
    FuncMonoMono operation; //区間クエリ
    FuncMonoMono setval; //点更新
    int N;
    vector<Mono> dat;
    Mono unitMono; //初期値であり単位元

    SegTree(int n, Mono unitm, FuncMonoMono _operation, FuncMonoMono _setval) : unitMono(unitm), operation(_operation), setval(_setval) {
        N = 1;
        while(N < n) N <<= 1;
        dat.resize(2*N-1, unitMono);
    }

    void update(int i, const Mono &val) { // 0-indexed
        i += (N - 1); //最下段に移動
        dat[i] = setval(dat[i],val);
        while(i > 0) { //上に向かって更新
            i = (i - 1) / 2;
            dat[i] = operation(dat[i*2+1], dat[i*2+2]);
        }
    }

    Mono _query(int a, int b, int k, int l, int r) {
        // [a,b)をみる。現在k,範囲[l,r)。0-indexed。
        if(r <= a or b <= l) return unitMono; //範囲外
        if(a <= l and r <= b) return dat[k]; //被覆
        Mono vl = _query(a, b, 2*k+1, l, (l+r)/2);
        Mono vr = _query(a, b, 2*k+2, (l+r)/2, r);
        return operation(vl, vr);
    }

    Mono query(int a, int b){ //[a,b)
        return _query(a,b,0,0,N);
    }

    inline Mono operator[](int i){
        return dat[i+N-1];
    }

};
vector<P> ans;
map<ll,ll> pos;
priority_queue<pair<ll,P>, vector<pair<ll,P>>, greater<pair<ll,P>>> Q;

// 範囲から左最小値を求めてQに入れる
void solve(ll l, ll r, SegTree<> &seg1, SegTree<> &seg2){
    if(l>r) return;
    ll x;
    if(l%2==0) x=seg1.query(l,r+1);
    else x=seg2.query(l,r+1);
    Q.emplace(x,(P){l,r});
}

// 範囲と左最小値から右最小値を求めてansに入れ、3つの範囲をsolveする。
void go(ll l, ll r, SegTree<> &seg1, SegTree<> &seg2){
    ll x,y;
    if(l%2==0) {
        x=seg1.query(l,r+1);
        y=seg2.query(pos[x],r+1);
    }
    else{
        x=seg2.query(l,r+1);
        y=seg1.query(pos[x],r+1);
    }
    ans.emplace_back(x,y);
    solve(l,pos[x]-1, seg1, seg2);
    solve(pos[x]+1,pos[y]-1, seg1, seg2);
    solve(pos[y]+1,r, seg1, seg2);
}


//--MAIN-----------------------------------
void Main() {
    ll N; cin>>N;
    vector<ll> A(N);
    rep(i,N) cin>>A[i];
    rep(i,N){
        pos[A[i]]=i;
    }
    // RMQ
    SegTree<> seg1(N+1,INF2,[](ll a, ll b){return min(a,b);}, [](ll a, ll b){return b;});
    SegTree<> seg2(N+1,INF2,[](ll a, ll b){return min(a,b);}, [](ll a, ll b){return b;});

    rep(i,N){
        if(i%2==0) seg1.update(i,A[i]);
        if(i%2==1) seg2.update(i,A[i]);
    }

    solve(0,N-1,seg1,seg2);
    while(!Q.empty()){
        ll l=Q.top().second.first;
        ll r=Q.top().second.second;
        Q.pop();
        go(l,r,seg1,seg2);
    }
    for(auto pe: ans){
        ll x=pe.first;
        ll y=pe.second;
        cout<< x SP y SP "";
    }
    cout<<"\n";

}

//--START----------------------------------
int main() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    Main();
}
//-----------------------------------------


Measured memory_bytes: 26528