#pragma region Include/Defines
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <limits.h>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <memory.h>
#include <string.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <functional>
#include <cassert>
#include <map>
#include <set>
#include <iostream>
#include <queue>
#include <time.h>

using namespace std;
typedef long long lli;
typedef vector<int> vi;
typedef vector<lli> vli;
typedef pair<int, int> pii;
typedef pair<lli, lli> pll;
typedef vector<pii> vpii;
typedef vector <pll> vpll;
typedef long double ld;
#define all(a) std::begin(a), std::end(a)

const int INF = 0x3f3f3f3f;
const lli LINF = 0x3f3f3f3f3f3f3f3f;

template<typename T, typename T2> inline void _max(T &a, T2 b) { a = max((T)a, (T)b); }
template<typename T, typename T2> inline void _min(T &a, T2 b) { a = min((T)a, (T)b); }

#ifdef _DEBUG
#define epr(...) fprintf(stderr,__VA_ARGS__)
#else
#define epr(...) 
#endif
#pragma endregion

const int MAX = 2e5 + 10;
int n, p[MAX], q[MAX];
int pos[MAX], used[MAX];
set<pii> segs;
set<int> s;

struct SegmentTree {
private:
	int na, parity;
	lli t[4 * MAX];

	lli merge(lli &left, lli &right) {
		lli res = left < right ? left : right;
		return res;
	}

	void build(int v, int tl, int tr) {
		if (tl == tr) {
			t[v] = tl % 2 == parity ? p[tl] : INF;
			return;
		}
		int tm = (tl + tr) / 2;
		build(2 * v, tl, tm);
		build(2 * v + 1, tm + 1, tr);
		t[v] = merge(t[2 * v], t[2 * v + 1]);
	}

	lli query(int v, int tl, int tr, int l, int r) {
		if (l > r) return INF;
		if (tl == l && tr == r)
			return t[v];

		int tm = (tl + tr) / 2;
		lli lRes = query(2 * v, tl, tm, l, min(r, tm));
		lli rRes = query(2 * v + 1, tm + 1, tr, max(l, tm + 1), r);
		lli res = merge(lRes, rRes);
		return res;
	}
public:
	SegmentTree() {
	}
	SegmentTree(int _na, int _parity) {
		na = _na, parity = _parity;
		build(1, 0, na - 1);
	}

	lli query(int l, int r) { return query(1, 0, na - 1, l, r); }
};

SegmentTree t[2];

void clear() {
}

void read() {
	for (int i = 0; i < n; i++) scanf("%d", &p[i]);
	for (int i = 0; i < n; i++) p[i]--;
	for (int i = 0; i < n; i++) pos[p[i]] = i;
}

pii split(int position) {
	auto it = prev(segs.lower_bound({ position, INF }));
	pii segment = *it;
	segs.erase(it);
	s.erase(t[segment.first & 1].query(segment.first, segment.second));
	int len = segment.second - segment.first + 1;
	pii res = { -1, -1 };
	if (position > segment.first) {
		pii seg = { segment.first, position - 1 };
		if ((position - segment.first) % 2 != len % 2) res = seg;
		segs.insert(seg);
		s.insert(t[seg.first & 1].query(seg.first, seg.second));
	}
	if (position < segment.second) {
		pii seg = { position + 1, segment.second };
		if ((position - segment.first) % 2 == len % 2) res = seg;
		segs.insert(seg);
		s.insert(t[seg.first & 1].query(seg.first, seg.second));
	}
	return res;
}

void solve() {
	for (int i = 0; i < 2; i++) t[i] = SegmentTree(n, i);

	memset(q, -1, sizeof(q));
	memset(used, 0, sizeof(used));
	int nq = 0;
	segs.clear();
	segs.insert({ 0, n - 1 });
	s.insert(t[0].query(0, n -1));

	while (!s.empty()) {
		auto curVal = *s.begin();
		int position = pos[curVal];
		
		pii pairSeg = split(position);
		int pairVal = t[1 ^ (position & 1)].query(pairSeg.first, pairSeg.second);

		split(pos[pairVal]);

		if (pos[curVal] < pos[pairVal])
			q[nq] = curVal, q[nq + 1] = pairVal;
		else 
			q[nq] = pairVal, q[nq + 1] = curVal;
		nq += 2;
	}

	for (int i = 0; i < nq; i++)
		printf("%d ", q[i] + 1);
	printf("\n");
}

int main() {
#ifdef _LOCAL_VAN
	freopen("in.txt", "r", stdin);
#endif
	while (scanf("%d", &n) == 1) {
		clear();
		read();
		solve();
#ifndef _LOCAL_VAN
		return 0;
#endif
	}
	return 0;
}

Measured memory_bytes: 26368