#[allow(unused_macros)]
macro_rules! parse_line {
    ( $t:ty ) => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            iter.next().unwrap().parse::<$t>().unwrap()
        }
    );

    ( $( $t:ty), +) => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            ( $(iter.next().unwrap().parse::<$t>().unwrap()),* )
        }
    );
}

#[allow(unused_macros)]
macro_rules! read_line {
    () => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            line.pop();
            line
        }
    )
}

#[allow(unused_macros)]
macro_rules! parse_vec {
    ( $t:ty ) => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            let iter = line.split_whitespace();
            iter.map(|v| v.parse::<$t>().unwrap()).collect::<Vec<_>>()
        }
    )
}

use std::rc::Rc;
use std::cell::RefCell;

fn init_(k: usize, l:usize, r:usize, rmq: Rc<RefCell<Vec<(usize, usize)>>>, vs: &Vec<usize>) -> (usize, usize) {
    use std::cmp::min;

    if r-l==1 {
        if l < vs.len() {
            rmq.borrow_mut()[k] = (vs[l], l);
        } else {
            rmq.borrow_mut()[k] = (std::usize::MAX, l);
        }
    } else {
        let chl = k*2 + 1;
        let chr = k*2 + 2;

        let lv = init_(chl, l, (l+r)/2, rmq.clone(), vs);
        let rv = init_(chr, (l+r)/2, r, rmq.clone(), vs);
        if lv.0 < rv.0 {
            rmq.borrow_mut()[k] = lv;
        } else {
            rmq.borrow_mut()[k] = rv;
        }
    }

    rmq.borrow()[k]
}

fn init(vs: Vec<usize>) -> Vec<(usize, usize)> {
    let n_ = vs.len();
    let mut n = 1;
    while n < n_ {
        n *= 2;
    }

    let mut rmq = Rc::new(RefCell::new(vec![(std::usize::MAX, std::usize::MAX); 2*n-1]));

    init_(0, 0, n, rmq.clone(), &vs);

    Rc::try_unwrap(rmq).ok().unwrap().into_inner()
}

// min value in [a, b)
fn query_(a: usize, b: usize, k: usize, l: usize, r: usize, rmq: &Vec<(usize, usize)>) -> (usize, usize) {
    use std::cmp::min;

    //println!("a,b,l,r = {}, {}, {}, {}", a,b,l,r);

    if r <= a || b <= l {
        return (std::usize::MAX, std::usize::MAX)
    }

    if a <= l && r <= b {
        rmq[k]
    } else {
        let vl = query_(a,b,k*2+1, l, (l+r)/2, rmq);
        let vr = query_(a,b,k*2+2, (l+r)/2, r, rmq);
        if vl.0 < vr.0 {
            vl
        } else {
            vr
        }
    }
}

fn query(a: usize, b: usize, rmq: &Vec<(usize, usize)>) -> (usize, usize) {
    let n = rmq.len();

    query_(a,b,0,0,(n+1)/2,rmq)
}
fn solve(ps: Vec<usize>) -> Vec<usize> {
    use std::collections::BinaryHeap;

    let n = ps.len();

    let mut evs = Vec::new();
    let mut odds = Vec::new();

    for (i, &p) in ps.iter().enumerate() {
        if i % 2 == 0 {
            evs.push(p);
        } else {
            odds.push(p);
        }
    }

    let evs = init(evs);
    let odds = init(odds);

    //println!("evs = {:?}", evs);
    //println!("odds = {:?}", odds);

    let mut ans: Vec<usize> = Vec::new();
    let mut heap = BinaryHeap::new();

    heap.push(Range{pri: evs[0].0, range:(0,n)});

    while !heap.is_empty() {

        let range = heap.pop().unwrap();
        let (a,b) = range.range;
        //println!("a,b = {}, {}", a,b);

        let (min_p, pos_l) =  if (a % 2) == 0 {
            query((a+a%2)/2, (b+b%2)/2, &evs)
        } else {
            query(a/2, b/2, &odds)
        };

        //println!("min_p, pos_l = {}, {}", min_p, pos_l);

        ans.push(min_p);

        let l = pos_l*2 + (a % 2);

        if a < l {
            let (pal, _) = if a % 2 == 0 {
                query((a+a%2)/2, (l+l%2)/2, &evs)
            } else {
                query(a/2, l/2, &odds)
            };
            //println!("a < l: ({}, {})", a, l);
            heap.push(Range{ pri:pal, range:(a, l)});
        }

        //println!("l, b, odds = {} {} {:?}", l, b, odds);

        let (pr, pos_r) = if l % 2 == 0 {
            query(l/2, b/2, &odds)
        } else {
            query((l+l%2)/2, (b+b%2)/2, &evs)
        };
        ans.push(pr);

        //println!("pos_r = {}", pos_r);

        let r = pos_r * 2 + if l % 2 == 1 { 0 } else { 1 };

        if l+1 < r {
            let l = l+1;
            let (plr, _) = if l % 2 == 0 {
                query((l+l%2)/2, (r+r%2)/2, &evs)
            } else {
                query(l/2, r/2, &odds)
            };
            //println!("l+1 < r: ({}, {})", l, r);
            heap.push(Range {pri: plr, range:(l,r)});
        }

        if r+1 < b {
            let r = r+1;
            let (prb, _) = if r % 2 == 0 {
                query((r+r%2)/2, (b+b%2)/2, &evs)
            } else {
                query(r/2, b/2, &odds)
            };

            //println!("r+1 < b: ({}, {})", r, b);
            heap.push(Range {pri: prb, range:(r, b)});
        }

        //println!("ans = {:?}", ans);
        //println!("a,l,r,b = {},{},{},{}", a,l,r,b);
        //println!("heap.len() = {}", heap.len());
        assert!(ans.len() <= n);
    }

    ans
}

use std::cmp::Ordering;

#[derive(PartialEq)]
struct Range {
    pri: usize,
    range: (usize, usize)
}

impl Eq for Range {}

impl PartialOrd for Range {
    fn partial_cmp(&self, other: &Range) -> Option<Ordering> {
        other.pri.partial_cmp(&self.pri)
    }
}

impl Ord for Range {
    fn cmp(&self, other: &Range) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

fn main() {
    read_line!();

    let ps = parse_vec!(usize);
    println!("{}", solve(ps).iter().map(|p| p.to_string()).collect::<Vec<String>>().join(" "));
}




Measured memory_bytes: 19412