#include <iostream>
#include <vector>
#include <algorithm>

#undef max
#undef min

using namespace std;

void SolveA()
{
	size_t N;
	cin >> N;
	size_t cnt1 = 0;
	size_t cnt2 = 0;
	size_t cnt4 = 0;
	for (size_t i = 0; i < N; ++i)
	{
		size_t tmp;
		cin >> tmp;
		if (!(tmp % 4))
			++cnt4;
		else if (!(tmp % 2))
			++cnt2;
		else
			++cnt1;
	}

	size_t lastType = 4;
	for (size_t i = 0; i < N; ++i)
	{
		if (lastType == 4 && cnt1 > 0)
		{
			--cnt1;
			lastType = 1;
		}
		else if (lastType >= 2 && cnt2 > 0)
		{
			--cnt2;
			lastType = 2;
		}
		else if (cnt4 > 0)
		{
			--cnt4;
			lastType = 4;
		}
		else
		{
			cout << "No";
			return;
		}
	}

	cout << "Yes";
}

void SolveB()
{
	int X[100][100];
	size_t H, W;
	cin >> H >> W;
	size_t N;
	cin >> N;
	int iCur = 0;
	int jCur = 0;
	int dir = 1;
	for (size_t i = 0; i < N; ++i)
	{
		size_t a;
		cin >> a;
		for (size_t j = 0; j < a; ++j)
		{
			X[iCur][jCur] = i + 1;
			jCur += dir;
			if (jCur == W)
			{
				jCur = W - 1;
				dir = -1;
				++iCur;
			}
			else if (jCur == -1)
			{
				jCur = 0;
				dir = 1;
				++iCur;
			}
		}
	}

	for (size_t i = 0; i < H; ++i)
	{
		for (size_t j = 0; j < W; ++j)
			cout << X[i][j] << " ";
		cout << "\n";
	}
}

struct sMyRange
{
	size_t lBound, rBound, lPos, rPos;
};

size_t GetMinPos(
	const vector<vector<size_t>>& F,
	size_t lQ, 
	size_t rQ,
	size_t iInterval,
	size_t nLevel,
	const vector<size_t>& p,
	bool even)
{
	size_t levelSize = static_cast<size_t>(int(1) << nLevel);
	size_t lI = iInterval * levelSize;
	size_t rI = (iInterval + 1) * levelSize - 1;

	if (lQ <= lI && rQ >= rI)
		return F[nLevel][iInterval];

	size_t minValue = p.size() + 1;
	size_t ans = p.size();
	if (lQ < lI + levelSize / 2)
	{
		ans = GetMinPos(F, lQ, rQ, iInterval * 2, nLevel - 1, p, even);
		minValue = p[2 * ans + (even ? 0 : 1)];
	}
	if (rQ >= lI + levelSize / 2)
	{
		size_t pos = GetMinPos(F, lQ, rQ, iInterval * 2 + 1, nLevel - 1, p, even);
		if (p[2 * pos + (even ? 0 : 1)] < minValue)
			ans = pos;
	}

	return ans;
}

sMyRange CreateRange(
	const vector<vector<size_t>>& Feven,
	const vector<vector<size_t>>& Fodd,
	const vector<size_t>& p,
	size_t l,
	size_t r)
{
	sMyRange res;
	res.lBound = l;
	res.rBound = r;

	size_t minEven = (l+1) / 2;
	size_t minOdd = l / 2;
	size_t maxEven = r / 2;
	size_t maxOdd = (r - 1) / 2;


	if (!(l % 2))
	{
		res.lPos = GetMinPos( Feven, minEven, maxEven, 0, Feven.size() - 1, p, true );		
		res.rPos = GetMinPos(Fodd, res.lPos, maxOdd, 0, Fodd.size() - 1, p, false);
		res.lPos *= 2;
		res.rPos *= 2;
		++res.rPos;
	}
	else
	{
		res.lPos = GetMinPos(Fodd, minOdd, maxOdd, 0, Fodd.size() - 1, p, false);
		res.rPos = GetMinPos(Feven, res.lPos+1, maxEven, 0, Feven.size() - 1, p, true);
		res.lPos *= 2;
		++res.lPos;
		res.rPos *= 2;		
	}

	return res;
}

void SolveC()
{
	size_t N;
	cin >> N;
	vector<size_t> p(N);
	for (size_t i = 0; i < N; ++i)
		cin >> p[i];

	size_t nLevels = 1;
	size_t cnt = 1;
	while (cnt*2 < N)
	{
		++nLevels;
		cnt *= 2;
	}

	size_t inf = N + 1;

	while (p.size() < 2*cnt)
		p.push_back(inf);

	size_t curCnt = cnt;
	vector< vector<size_t> > Feven(nLevels), Fodd(nLevels);
	for (size_t i = 0; i < nLevels; ++i)
	{
		Feven[i].assign(curCnt, inf);
		Fodd[i].assign(curCnt, inf);
		curCnt /= 2;
	}

	for (size_t i = 0; i < cnt; ++i)
	{
		Feven[0][i] = i;
		Fodd[0][i] = i;
	}

	curCnt = cnt / 2;
	for (size_t i = 1; i < nLevels; ++i)
	{
		for (size_t j = 0; j < curCnt; ++j)
		{
			size_t e1 = Feven[i - 1][2 * j];
			size_t e2 = Feven[i - 1][2 * j+1];
			Feven[i][j] = (p[2*e1] < p[2*e2]) ? Feven[i - 1][2 * j] : Feven[i - 1][2 * j+1];
			size_t o1 = Fodd[i - 1][2 * j];
			size_t o2 = Fodd[i - 1][2 * j+1];
			Fodd[i][j] = (p[2*o1+1] < p[2*o2+1]) ? Fodd[i - 1][2 * j] : Fodd[i - 1][2 * j + 1];
		}

		curCnt /= 2;
	}

	vector<sMyRange> v;
	v.resize(N);
	size_t heapSize = 1;
	v[0] = CreateRange(Feven, Fodd, p, 0, N - 1);

	auto rangeCmp = [&p](const sMyRange& r1, const sMyRange& r2) -> bool { return p[r1.lPos] > p[r2.lPos]; };
	for (size_t i = 0; 2 * i < N; ++i)
	{
		sMyRange r = v[0];

		cout << p[r.lPos] << " " << p[r.rPos] << " ";

		pop_heap(v.begin(), v.begin() + heapSize, rangeCmp);
		--heapSize;

		if (r.lPos > r.lBound)
		{
			v[heapSize] = CreateRange(Feven, Fodd, p, r.lBound, r.lPos - 1);
			++heapSize;
			push_heap(v.begin(), v.begin() + heapSize, rangeCmp);
		}

		if (r.lPos + 1 < r.rPos)
		{
			v[heapSize] = CreateRange(Feven, Fodd, p, r.lPos + 1, r.rPos-1);
			++heapSize;
			push_heap(v.begin(), v.begin() + heapSize, rangeCmp);
		}

		if (r.rPos < r.rBound)
		{
			v[heapSize] = CreateRange(Feven, Fodd, p, r.rPos + 1, r.rBound);
			++heapSize;
			push_heap(v.begin(), v.begin() + heapSize, rangeCmp);
		}
	}
}

int main()
{
	SolveC();
	return 0;
}


Measured memory_bytes: 14492