Let N be a positive even number.
We have a permutation of (1, 2, ..., N), p = (p_1, p_2, ..., p_N).
Snuke is constructing another permutation of (1, 2, ..., N), q, following the procedure below.
First, let q be an empty sequence.
Then, perform the following operation until p becomes empty:
 - Select two adjacent elements in p, and call them x and y in order. Remove x and y from p (reducing the length of p by 2), and insert x and y, preserving the original order, at the beginning of q.
When p becomes empty, q will be a permutation of (1, 2, ..., N).
Find the lexicographically smallest permutation that can be obtained as q.

-----Constraints-----
 - N is an even number.
 - 2 ≤ N ≤ 2 × 10^5
 - p is a permutation of (1, 2, ..., N).

-----Input-----
Input is given from Standard Input in the following format:
N
p_1 p_2 ... p_N

-----Output-----
Print the lexicographically smallest permutation, with spaces in between.

-----Sample Input-----
4
3 2 4 1

-----Sample Output-----
3 1 2 4

The solution above is obtained as follows:pq(3, 2, 4, 1)()↓↓(3, 1)(2, 4)↓↓()(3, 1, 2, 4)

Difficulty: VERY_HARD

Solutions:
import sys
input = sys.stdin.buffer.readline

class SparseTable:

	def __init__(self, N, A):
		self.N = N
		self.logN = N.bit_length()
		self.A = A
		self.table = [[i for i in range(N)]]
		for k in range(self.logN):
			tab = []
			for i in range(self.N - (1 << k + 1) + 1):
				ind1 = self.table[-1][i]
				ind2 = self.table[-1][i + (1 << k)]
				if self.A[ind1] <= self.A[ind2]:
					tab.append(ind1)
				else:
					tab.append(ind2)
			self.table.append(tab)

	def query_min(self, l, r):
		k = (r - l).bit_length() - 1
		indl = self.table[k][l]
		indr = self.table[k][r - (1 << k)]
		if self.A[indl] <= self.A[indr]:
			return (self.A[indl], indl)
		return (self.A[indr], indr)
import heapq as hp
N = int(input())
A = list(map(int, input().split()))

def main():
	SP1 = SparseTable((N + 1) // 2, A[::2])
	SP2 = SparseTable(N // 2, A[1::2])
	ans = []
	q = []
	(v, k) = SP1.query_min(0, N // 2)
	dic = {}
	dic[v] = (k, 0, N // 2, True)
	hp.heappush(q, v)
	for _ in range(N // 2):
		valuea = hp.heappop(q)
		(ka, l, r, is1) = dic[valuea]
		ans.append(str(valuea))
		if is1:
			(valueb, kb) = SP2.query_min(ka, r)
			if ka < kb:
				(m2, nk2) = SP2.query_min(ka, kb)
				hp.heappush(q, m2)
				dic[m2] = (nk2, ka, kb + 1, False)
			if l < ka:
				(m1, nk1) = SP1.query_min(l, ka)
				hp.heappush(q, m1)
				dic[m1] = (nk1, l, ka, True)
			if kb + 1 < r:
				(m3, nk3) = SP1.query_min(kb + 1, r)
				hp.heappush(q, m3)
				dic[m3] = (nk3, kb + 1, r, True)
		else:
			(valueb, kb) = SP1.query_min(ka + 1, r)
			if ka + 1 < kb:
				(m1, nk1) = SP1.query_min(ka + 1, kb)
				hp.heappush(q, m1)
				dic[m1] = (nk1, ka + 1, kb, True)
			if l < ka:
				(m2, nk2) = SP2.query_min(l, ka)
				hp.heappush(q, m2)
				dic[m2] = (nk2, l, ka + 1, False)
			if kb < r - 1:
				(m3, nk3) = SP2.query_min(kb, r - 1)
				hp.heappush(q, m3)
				dic[m3] = (nk3, kb, r, False)
		ans.append(str(valueb))
	print(' '.join(ans))
main()


class segment_tree:

	def __init__(self, N, operator_M, e_M):
		self.op_M = operator_M
		self.e_M = e_M
		self.N0 = 1 << (N - 1).bit_length()
		self.dat = [self.e_M] * (2 * self.N0)

	def build(self, initial):
		self.dat[self.N0:self.N0 + len(initial)] = initial[:]
		for k in range(self.N0 - 1, 0, -1):
			self.dat[k] = self.op_M(self.dat[2 * k], self.dat[2 * k + 1])

	def update(self, k, x):
		k += self.N0
		self.dat[k] = x
		k //= 2
		while k:
			self.dat[k] = self.op_M(self.dat[2 * k], self.dat[2 * k + 1])
			k //= 2

	def query(self, L, R):
		L += self.N0
		R += self.N0 + 1
		sl = sr = self.e_M
		while L < R:
			if R & 1:
				R -= 1
				sr = self.op_M(self.dat[R], sr)
			if L & 1:
				sl = self.op_M(sl, self.dat[L])
				L += 1
			L >>= 1
			R >>= 1
		return self.op_M(sl, sr)

	def get(self, k):
		return self.dat[k + self.N0]
import sys
read = sys.stdin.read
readline = sys.stdin.readline
sys.setrecursionlimit(10 ** 5)
(n, *p) = map(int, read().split())
INF = 1 << 30
p += [INF, INF]

def argmin(i, j):
	if p[i] < p[j]:
		return i
	else:
		return j
even = segment_tree(n // 2 + 1, argmin, n)
odd = segment_tree(n // 2 + 1, argmin, n + 1)
even.build(range(0, n + 2, 2))
odd.build(range(1, n + 2, 2))
ans = [0] * n

def get(i, j):
	return odd.query(i // 2, (j - 1) // 2) if i % 2 else even.query(i // 2, (j - 1) // 2)
from heapq import *
k = get(0, n - 1)
q = [(p[k], k, 0, n - 1)]
for I in range(n // 2):
	(v, k, i, j) = heappop(q)
	l = even.query((k + 1) // 2, j // 2) if i % 2 else odd.query((k + 1) // 2, j // 2)
	ans[2 * I] = v
	ans[2 * I + 1] = p[l]
	if i < k + 1:
		kk = get(i, k - 1)
		heappush(q, (p[kk], kk, i, k - 1))
	if k + 1 < l - 1:
		kk = get(k + 1, l - 1)
		heappush(q, (p[kk], kk, k + 1, l - 1))
	if l + 1 < j:
		kk = get(l + 1, j)
		heappush(q, (p[kk], kk, l + 1, j))
print(*ans)


from sys import stdin
import heapq

def make_ST(n, first):
	i = 0
	ret = []
	while 2 ** (i - 1) < n:
		for j in range(2 ** i):
			ret.append(first)
		i += 1
	return ret

def RMQ_update_point(num, point, tree):
	i = (len(tree) - 1) // 2 + point
	tree[i] = num
	while i > 0:
		i = (i - 1) // 2
		tree[i] = min(tree[i * 2 + 2], tree[i * 2 + 1])
	return

def RMQ_query(a, b, k, l, r, tree):
	if r <= a or b <= l:
		return (float('inf'), float('inf'))
	if a <= l and r <= b:
		return tree[k]
	c1 = RMQ_query(a, b, 2 * k + 1, l, (l + r) // 2, tree)
	c2 = RMQ_query(a, b, 2 * k + 2, (l + r) // 2, r, tree)
	return min(c1, c2)

def want(L, R):
	if L >= R:
		return
	elif L + 1 == R:
		heapq.heappush(q, (p[L], p[R], float('inf'), float('-inf'), float('inf'), float('-inf')))
		return
	if L % 2 == 0:
		(nx, xind) = RMQ_query(L, R + 1, 0, 0, (len(emin) + 1) // 2, emin)
		(ny, yind) = RMQ_query(xind + 1, R + 1, 0, 0, (len(omin) + 1) // 2, omin)
	else:
		(nx, xind) = RMQ_query(L, R + 1, 0, 0, (len(omin) + 1) // 2, omin)
		(ny, yind) = RMQ_query(xind + 1, R + 1, 0, 0, (len(emin) + 1) // 2, emin)
	heapq.heappush(q, (nx, ny, xind, yind, L, R))
	return
N = int(input())
p = list(map(int, stdin.readline().split()))
omin = make_ST(N, (float('inf'), float('inf')))
emin = make_ST(N, (float('inf'), float('inf')))
for i in range(N):
	if i % 2 == 0:
		RMQ_update_point((p[i], i), i, emin)
	else:
		RMQ_update_point((p[i], i), i, omin)
q = []
want(0, N - 1)
ans = []
while len(q) > 0:
	(x, y, xi, yi, NL, NR) = heapq.heappop(q)
	ans.append(x)
	ans.append(y)
	want(NL, xi - 1)
	want(xi + 1, yi - 1)
	want(yi + 1, NR)
print(*ans)


from heapq import heappop, heappush
INF = 10 ** 30

class Rmin:

	def __init__(self, size):
		self.n = 1
		while self.n < size:
			self.n *= 2
		self.node = [INF] * (2 * self.n - 1)

	def Access(self, x):
		return self.node[x + self.n - 1]

	def Update(self, x, val):
		x += self.n - 1
		self.node[x] = val
		while x > 0:
			x = (x - 1) // 2
			self.node[x] = min(self.node[2 * x + 1], self.node[2 * x + 2])
		return

	def Get(self, l, r):
		(L, R) = (l + self.n, r + self.n)
		s = INF
		while L < R:
			if R & 1:
				R -= 1
				s = min(s, self.node[R - 1])
			if L & 1:
				s = min(s, self.node[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return s
n = int(input())
a = list(map(int, input().split()))
(even, odd) = (Rmin(n), Rmin(n))
for i in range(n):
	if i % 2 == 0:
		even.Update(i, a[i] * 10 ** 7 + i)
	else:
		odd.Update(i, a[i] * 10 ** 7 + i)
d = dict()

def search(l, r):
	if l % 2 == 0:
		p = even.Get(l, r + 1)
		q = odd.Get(p % 10 ** 7 + 1, r + 1)
	else:
		p = odd.Get(l, r + 1)
		q = even.Get(p % 10 ** 7 + 1, r + 1)
	return (p, q)
(x, y) = search(0, n - 1)
d[x % 10 ** 7] = (y, 0, n - 1)
que = [x]
ans = []
while que:
	x = heappop(que)
	(y, l, r) = d[x % 10 ** 7]
	ans += [x // 10 ** 7, y // 10 ** 7]
	if l != x % 10 ** 7:
		(p, q) = search(l, x % 10 ** 7 - 1)
		d[p % 10 ** 7] = (q, l, x % 10 ** 7 - 1)
		heappush(que, p)
	if r != y % 10 ** 7:
		(p, q) = search(y % 10 ** 7 + 1, r)
		d[p % 10 ** 7] = (q, y % 10 ** 7 + 1, r)
		heappush(que, p)
	if x % 10 ** 7 + 1 != y % 10 ** 7:
		(p, q) = search(x % 10 ** 7 + 1, y % 10 ** 7 - 1)
		d[p % 10 ** 7] = (q, x % 10 ** 7 + 1, y % 10 ** 7 - 1)
		heappush(que, p)
print(*ans)


def segfunc(x, y):
	if y[0] > x[0]:
		return x
	else:
		return y
ide_ele = (float('inf'), -1)

class SegTree:

	def __init__(self, init_val, segfunc, ide_ele):
		n = len(init_val)
		self.segfunc = segfunc
		self.ide_ele = ide_ele
		self.num = 1 << (n - 1).bit_length()
		self.tree = [ide_ele] * 2 * self.num
		for i in range(n):
			self.tree[self.num + i] = init_val[i]
		for i in range(self.num - 1, 0, -1):
			self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

	def update(self, k, x):
		k += self.num
		self.tree[k] = x
		while k > 1:
			self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
			k >>= 1

	def query(self, l, r):
		res = self.ide_ele
		l += self.num
		r += self.num
		while l < r:
			if l & 1:
				res = self.segfunc(res, self.tree[l])
				l += 1
			if r & 1:
				res = self.segfunc(res, self.tree[r - 1])
			l >>= 1
			r >>= 1
		return res
import heapq
N = int(input())
p = list(map(int, input().split()))
n = N // 2
op = [(p[2 * i + 1], 2 * i + 1) for i in range(n)]
ep = [(p[2 * i], 2 * i) for i in range(n)]
oseg = SegTree(op, segfunc, ide_ele)
eseg = SegTree(ep, segfunc, ide_ele)

def first(l, r):
	if l >= r:
		return (-1, -1, -1, -1)
	if l % 2 == 0:
		(val, index) = eseg.query(l // 2, r // 2)
		(val2, index2) = oseg.query(index // 2, r // 2)
		return (val, val2, index, index2)
	else:
		(val, index) = oseg.query(l // 2, r // 2)
		(val2, index2) = eseg.query(index // 2 + 1, r // 2 + 1)
		return (val, val2, index, index2)
(val, val2, index, index2) = first(0, N)
que = [((val, val2), 0, N)]
heapq.heapify(que)
ans = []
while que:
	(tuple, l, r) = heapq.heappop(que)
	ans.append(tuple[0])
	ans.append(tuple[1])
	(val, val2, index, index2) = first(l, r)
	(val, val2, l1, r1) = first(l, index)
	if val != -1:
		heapq.heappush(que, ((val, val2), l, index))
	(val, val2, l2, r2) = first(index + 1, index2)
	if val != -1:
		heapq.heappush(que, ((val, val2), index + 1, index2))
	(val, val2, l3, r3) = first(index2 + 1, r)
	if val != -1:
		heapq.heappush(que, ((val, val2), index2 + 1, r))
print(*ans)