Problem:
Score : 800 points

Problem Statement

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 1

4
3 2 4 1

Sample Output 1

3 1 2 4

The solution above is obtained as follows:

p

q

(3, 2, 4, 1)

()

↓

↓

(3, 1)

(2, 4)

↓

↓

()

(3, 1, 2, 4)

Sample Input 2

2
1 2

Sample Output 2

1 2

Sample Input 3

8
4 6 3 2 8 5 7 1

Sample Output 3

3 1 2 7 4 6 8 5

The solution above is obtained as follows:

p

q

(4, 6, 3, 2, 8, 5, 7, 1)

()

↓

↓

(4, 6, 3, 2, 7, 1)

(8, 5)

↓

↓

(3, 2, 7, 1)

(4, 6, 8, 5)

↓

↓

(3, 1)

(2, 7, 4, 6, 8, 5)

↓

↓

()

(3, 1, 2, 7, 4, 6, 8, 5)

Solution in C# (Mono 4.6.2.0) (judge verdict: Runtime Error)

using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Numerics;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using static System.Math;
using Debug = System.Diagnostics.Debug;
using LayoutKind = System.Runtime.InteropServices.LayoutKind;
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;


static class P
{
    static SegmentTree<Tuple<Tuple<int, int>, Tuple<int, int>>> segTree;
    static void Main()
    {
        int n = int.Parse(Console.ReadLine());
        var p = Console.ReadLine().Split().Select(int.Parse).ToArray();
        //その中で前から見て奇数番目にあるものの中で最小と、その後の区間の奇数番目
        //int n = 200000;
        //var p = Enumerable.Range(1, n).ToArray();


        var IdentityElement = new Tuple<int, int>(int.MaxValue, -1);
        segTree = new SegmentTree<Tuple<Tuple<int, int>, Tuple<int, int>>>(
            p.Select((x, y) =>
            new Tuple<Tuple<int, int>, Tuple<int, int>>(
                y % 2 == 0 ? new Tuple<int, int>(x, y) : IdentityElement, 
                y % 2 == 0 ? IdentityElement : new Tuple<int, int>(x, y))
            ).ToArray(),
            new Tuple<Tuple<int, int>, Tuple<int, int>>(IdentityElement, IdentityElement),
            (x, y) => new Tuple<Tuple<int, int>, Tuple<int, int>>(x.Item1.Item1 < y.Item1.Item1 ? x.Item1 : y.Item1, x.Item2.Item1 < y.Item2.Item1 ? x.Item2 : y.Item2)
        );
        int[] res = Solve(0, n);
        Console.WriteLine(string.Join(" ", res));
    }

    static int[] Solve(int l, int r)
    {
        if (l == r) return new int[0];
        var firstPivot = l % 2 == 0 ? segTree.Query(l, r).Item1 : segTree.Query(l, r).Item2;
        var secondPivot = l % 2 == 0 ? segTree.Query(firstPivot.Item2 + 1, r).Item2 : segTree.Query(firstPivot.Item2 + 1, r).Item1;
        
        var firstSection = Solve(l, firstPivot.Item2);
        var secondSection = Solve(firstPivot.Item2 + 1, secondPivot.Item2);
        var thirdSection = Solve(secondPivot.Item2 + 1, r);

        int aptr = 0;
        int bptr = 0;
        int cptr = 0;
        int[] res = new int[firstSection.Length + secondSection.Length + thirdSection.Length + 2];
        res[0] = firstPivot.Item1;
        res[1] = secondPivot.Item1;

        while (aptr < firstSection.Length && bptr < secondSection.Length && cptr < thirdSection.Length)
        {
            if (firstSection[aptr] < secondSection[bptr])
            {
                if (thirdSection[cptr] < firstSection[aptr])
                {
                    res[aptr + bptr + cptr + 2] = thirdSection[cptr];
                    res[aptr + bptr + cptr + 3] = thirdSection[cptr + 1];
                    cptr += 2;
                }
                else
                {
                    res[aptr + bptr + cptr + 2] = firstSection[aptr];
                    res[aptr + bptr + cptr + 3] = firstSection[aptr + 1];
                    aptr += 2;
                }
            }
            else
            {
                if (thirdSection[cptr] < secondSection[bptr])
                {
                    res[aptr + bptr + cptr + 2] = thirdSection[cptr];
                    res[aptr + bptr + cptr + 3] = thirdSection[cptr + 1];
                    cptr += 2;
                }
                else
                {
                    res[aptr + bptr + cptr + 2] = secondSection[bptr];
                    res[aptr + bptr + cptr + 3] = secondSection[bptr + 1];
                    bptr += 2;
                }
            }
        }

        while (aptr < firstSection.Length && bptr < secondSection.Length)
        {
            if (firstSection[aptr] < secondSection[bptr])
            {
                res[aptr + bptr + cptr + 2] = firstSection[aptr];
                res[aptr + bptr + cptr + 3] = firstSection[aptr + 1];
                aptr += 2;
            }
            else
            {
                res[aptr + bptr + cptr + 2] = secondSection[bptr];
                res[aptr + bptr + cptr + 3] = secondSection[bptr + 1];
                bptr += 2;
            }
        }
        while (aptr < firstSection.Length && cptr < thirdSection.Length)
        {
            if (firstSection[aptr] < thirdSection[cptr])
            {
                res[aptr + bptr + cptr + 2] = firstSection[aptr];
                res[aptr + bptr + cptr + 3] = firstSection[aptr + 1];
                aptr += 2;
            }
            else
            {
                res[aptr + bptr + cptr + 2] = thirdSection[cptr];
                res[aptr + bptr + cptr + 3] = thirdSection[cptr + 1];
                cptr += 2;
            }
        }
        while (bptr < firstSection.Length && cptr < thirdSection.Length)
        {
            if (secondSection[bptr] < thirdSection[cptr])
            {
                res[aptr + bptr + cptr + 2] = secondSection[bptr];
                res[aptr + bptr + cptr + 3] = secondSection[bptr + 1];
                bptr += 2;
            }
            else
            {
                res[aptr + bptr + cptr + 2] = thirdSection[cptr];
                res[aptr + bptr + cptr + 3] = thirdSection[cptr + 1];
                cptr += 2;
            }
        }

        while (aptr < firstSection.Length)
        {
            res[aptr + bptr + cptr + 2] = firstSection[aptr];
            res[aptr + bptr + cptr + 3] = firstSection[aptr + 1];
            aptr += 2;
        }
        while (bptr < secondSection.Length)
        {
            res[aptr + bptr + cptr + 2] = secondSection[bptr];
            res[aptr + bptr + cptr + 3] = secondSection[bptr + 1];
            bptr += 2;
        }
        while (cptr < thirdSection.Length)
        {
            res[aptr + bptr + cptr + 2] = thirdSection[cptr];
            res[aptr + bptr + cptr + 3] = thirdSection[cptr + 1];
            cptr += 2;
        }

        return res;
    }
}


class SegmentTree<T>
{
    public int Size { get; private set; }
    T IdentityElement;
    T[] Data;
    Func<T, T, T> Merge;
    int LeafCount;

    public SegmentTree(int size, T identityElement, Func<T, T, T> merge) : this(Enumerable.Repeat(identityElement, size).ToArray(), identityElement, merge) { }

    public SegmentTree(T[] elems, T identityElement, Func<T, T, T> merge)
    {
        Size = elems.Length;
        Merge = merge;
        IdentityElement = identityElement;
        LeafCount = 1;
        while (LeafCount < elems.Length) LeafCount <<= 1;

        Data = new T[LeafCount * 2];
        elems.CopyTo(Data, LeafCount);
        for (int i = LeafCount + elems.Length; i < LeafCount * 2; i++) Data[i] = identityElement;
        for (int i = LeafCount - 1; i >= 1; i--) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    public T this[int index]
    {
        get { return Data[LeafCount + index]; }
        set { Update(index, value); }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Update(int i, T x)
    {
        i += LeafCount;
        Data[i] = x;
        while (0 < (i >>= 1)) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Operate(int i, T x)
    {
        i += LeafCount;
        Data[i] = Merge(Data[i], x);
        while (0 < (i >>= 1)) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T Query(int l, int r)
    {
        l += LeafCount;
        T lRes = IdentityElement;
        r += LeafCount - 1;
        T rRes = IdentityElement;
        while (l <= r)
        {
            if (l % 2 == 1) lRes = Merge(lRes, Data[l]);
            if (r % 2 == 0) rRes = Merge(Data[r], rRes);
            l = (l + 1) / 2;
            r = (r - 1) / 2;
        }
        return Merge(lRes, rRes);
    }
}