#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

typedef long long ll;
typedef pair<int,int> PP;

/*
    freopen("input","r",stdin);
    freopen("output","w",stdout);
*/

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

typedef long long ll;
typedef pair<int,int> PP;

const int INF = 1E9;

class SegmentTreeNode {
public:
	int L, R, val;
	SegmentTreeNode *left, *right;
	SegmentTreeNode(int L, int R) {
		this->L = L;
		this->R = R;
		this->left = NULL;
		this->right = NULL;
		this->val = INF;
	}
};

SegmentTreeNode * build(int L, int R) {
	SegmentTreeNode * crt = new SegmentTreeNode(L, R);
	if (L == R) return crt;
	int M = L + (R - L) / 2;
	if (M >= L) crt->left = build(L, M);
	if (M + 1 <= R) crt->right = build(M + 1, R);
	return crt;
}

void destroy(SegmentTreeNode * root) {
	if (root->left != NULL) destroy(root->left);
	if (root->right != NULL) destroy(root->right);
	delete root;
	return;
}

ll query(int L, int R, SegmentTreeNode * root) {
	if (root == NULL) return INF;
	int l = root->L;
	int r = root->R;
	if (L == l && R == r) return root->val;
	int m = root->L + (root->R - root->L) / 2;
	if (R <= m) return query(L, R, root->left);
	if (L >= m + 1) return query(L, R, root->right);
	int vl = query(L, m, root->left);
	int vr = query(m + 1, R, root->right);
	return min(vl, vr);
}

void update(int idx, int val, SegmentTreeNode * root) {
	if (root == NULL) return;
	root->val = min(root->val, val);
	int mid = root->L + (root->R - root->L) / 2;
	if (root->L <= idx && idx <= mid) update(idx, val, root->left);
	if (mid + 1 <= idx && idx <= root->R) update(idx, val, root->right);
	return;
}

int DP[200010];

int R[200010];

struct node {
	int l;
	int r;
	int num;
};

bool operator < (node a, node b) {
	return a.num > b.num;
}

int main() {
    ios::sync_with_stdio(false);
    int N;
    cin >> N;
    SegmentTreeNode * T[2];
    T[0] = build(0, N-1);
    T[1] = build(0, N-1);
    for (int i = 0;i < N;i++) {
    	cin >> R[i];
    	DP[R[i]] = i;
    	update(i, R[i], T[i & 1]);
    }
    priority_queue<node> P;
    node p;
    p.l = 0;
    p.r = N - 1;
    p.num = query(0, N - 1, T[0]);
    P.push(p);
    vector<int> sol;
    while (P.size() > 0) {
    	p = P.top();
    	P.pop();
    	int s = p.l;
    	int b = p.r;
    	int idx = DP[p.num];
    	int ot = query(idx + 1, b, T[(idx + 1) & 1]);
    	int idx2 = DP[ot];
    	sol.push_back(p.num);
    	sol.push_back(ot);
    	if (s < idx - 1) {
    		node q;
    		q.l = s;
    		q.r = idx - 1;
    		q.num = query(q.l, q.r, T[q.l & 1]);
    		P.push(q);
    	}
    	if (idx + 1 < idx2 - 1) {
    		node q;
    		q.l = idx + 1;
    		q.r = idx2 - 1;
    		q.num = query(q.l, q.r, T[q.l & 1]);
    		P.push(q);
    	}
    	if (idx2 + 1 < b) {
    		node q;
    		q.l = idx2 + 1;
    		q.r = b;
    		q.num = query(q.l, q.r, T[q.l & 1]);
    		P.push(q);
    	}
    }
    for (int i = 0;i < sol.size();i++) {
    	if (i != 0) cout << ' ';
    	cout << sol[i];
    }
    cout << endl;
    return 0;
}

Measured memory_bytes: 41996