#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <utility>
#include <cstdlib>
#include <memory>
#include <queue>
#include <cassert>
#include <cmath>
#include <ctime>
#include <complex>
#include <bitset>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <numeric>

using namespace std;

#define ws ws_____________________
#define y1 y1_____________________
#define y0 y0_____________________
#define left left_________________
#define right right_______________
#define next next_________________
#define prev prev_________________
#define hash hash_________________

#define pb push_back
#define fst first
#define snd second
#define mp make_pair 
#define sz(C) ((int) (C).size())
#define forn(i, n) for (int i = 0; i < int(n); ++i)
#define ford(i, n) for (int i = int(n) - 1; i >= 0; --i)
#define all(C) begin(C), end(C)

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int,int> pii;
typedef pair<ll, ll> pll;
typedef vector<ll> vll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vii;
typedef long double ld;
typedef complex<double> cd;

#ifdef LOCAL
#define eprintf(args...) fprintf(stderr, args), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define FILE_NAME "a"


int n;
vi p;

bool read() {
	if  (scanf("%d", &n) < 1) {
		return 0;
	}
	p.resize(n);
	forn(i, n) {
		scanf("%d", &p[i]);
		--p[i];
	}
	return 1;
}

const int INF = 1e9;

struct SegmTree {
	vii t;
	int sz;

	SegmTree(int n = 0) {
		sz = 1;
		while (sz < n) sz *= 2;
		t.assign(sz * 2, mp(INF, -1));
	}

	pii get_min(int l, int r) {
		assert(l <= r);
		assert(r < sz);
		assert(0 <= l);
		l += sz;
		r += sz;
		pii res(INF, -1);
		while (l <= r) {
			res = min(res, t[l]);
			res = min(res, t[r]);
			l = (l + 1) >> 1;
			r = (r - 1) >> 1;
		}
		return res;
	}

	void put(int pos, int val) {
		int v = sz + pos;
		t[v] = mp(val, pos);
		v >>= 1;
		while (v) {
			t[v] = min(t[v * 2], t[v * 2 + 1]);
			v >>= 1;
		}
	}
};

int expand(int pos, int parity) {
	if  (pos == -1) {
		return -1;
	}
	if  (parity == 1) {
		return pos * 2 + 1;
	}
	return pos * 2;
}

vector<SegmTree> T;

struct Seg {
	int l, r;
	pii poses;

	Seg(int l, int r) : l(l), r(r) {
		assert(l < r);
		assert((r - l + 1) % 2 == 0);
		int pos = expand(T[l & 1].get_min(l / 2, (r - 1) / 2).snd, l & 1);
		int pos2 = expand(T[~l & 1].get_min((pos + 1) / 2, r / 2).snd, ~l & 1);
		poses = mp(pos, pos2);
	}

	pii calc() const {
		return mp(p[poses.fst], p[poses.snd]);
	}

	bool operator < (const Seg& s) const {
		return calc() < s.calc();
	}
};

void solve() {
	assert(n % 2 == 0);

	T.resize(2);
	forn(c, 2) {
		T[c] = SegmTree(n / 2);
	}
	forn(i, n) {
		T[i & 1].put(i / 2, p[i]);
	}

	vi q;
	set<Seg> segs;
	segs.insert(Seg(0, n - 1));
	forn(iter, n / 2) {
		assert(!segs.empty());
		auto mn = *segs.begin();
		segs.erase(segs.begin());
	
		auto vals = mn.calc();
		q.pb(vals.fst);
		q.pb(vals.snd);

		if  (mn.l <= mn.poses.fst - 1) {
			segs.insert(Seg(mn.l, mn.poses.fst - 1));
		}
		if  (mn.poses.fst + 1 <= mn.poses.snd - 1) {
			segs.insert(Seg(mn.poses.fst + 1, mn.poses.snd - 1));
		}
		if  (mn.poses.snd + 1 <= mn.r) {
			segs.insert(Seg(mn.poses.snd + 1, mn.r));
		}
	}

	forn(i, n) {
		printf("%d ", q[i] + 1);
	}
	puts("");
}

int main() {
#ifdef LOCAL
	freopen(FILE_NAME ".in", "r", stdin);
	// freopen(FILE_NAME ".out", "w", stdout);
#endif

	while (read()) {
		solve();
	}

#ifdef LOCAL
	cerr.precision(5);
	cerr << "Time: " << fixed << (double) clock() / CLOCKS_PER_SEC << endl;
#endif
	return 0;
}


Measured memory_bytes: 9716