#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <functional>
#include <algorithm>

/* for minimum range query */
template<typename T, typename U>
class SegmentTree {
 public:
  explicit SegmentTree<T>(unsigned long size, U fun, T def) : data_(),
                                                              fun_(fun),
                                                              def_(def),
                                                              max_(1ul) {
    while (size > max_) { max_ *= 2; }
    data_ = std::vector<T>(max_ * 2, def_);
  }
  void Init(const std::vector<T> &data) {
    for (unsigned long i = 0; i < data.size(); ++i) {
      Update(i, data[i]);
    }
  }
  void Update(unsigned long index, T a) {
    index += max_ - 1;
    data_[index] = a;
    while (index) {
      index = (index - 1) / 2;
      data_[index] = fun_(data_[index * 2 + 1], data_[index * 2 + 2]);
    }
  }
  T Query(unsigned long begin, unsigned long end) {
    return QueryInternal(begin, end, 0, 0, max_);
  }
 private:
  std::vector<T> data_;
  U fun_;
  T def_;
  unsigned long max_;
  T QueryInternal(unsigned long a, unsigned long b, unsigned long k, unsigned long l, unsigned long r) {
    // apply minimum query to range [a, b)
    // k: current node
    // [l, r): range of node k
    if (r <= a || b <= l) { return def_; }
    if (a <= l && r <= b) { return data_[k]; }
    else {
      auto x = QueryInternal(a, b, 2 * k + 1, l, (l + r) / 2);
      auto y = QueryInternal(a, b, 2 * k + 2, (l + r) / 2, r);
      return fun_(x, y);
    }
  }
};

template<typename T>
class MinCmp {
 public:
  T operator()(const T &x, const T &y) {
    return x < y ? x : y;
  }
};

template<typename T>
class RangeMinimum : public SegmentTree<T, MinCmp<T>> {
 public:
  explicit RangeMinimum<T>(unsigned long size)
      : SegmentTree<T, MinCmp<T>>(size, MinCmp<T>(), T::Max()) {}
};

template<typename T, typename U>
class KV {
 public:
  KV<T, U>(T key, U value) : key_(std::move(key)), value_(std::move(value)) {}
  T Key() const { return key_; }
  U Value() const { return value_; }
  void SetKey(const T key) { key_ = std::move(key); }
  void SetValue(const U value) { value_ = std::move(value); }
  bool operator<(const KV<T, U> &r) const { return key_ < r.key_; }
  bool operator<=(const KV<T, U> &r) const { return key_ <= r.key_; }
  bool operator>(const KV<T, U> &r) const { return key_ > r.key_; }
  bool operator>=(const KV<T, U> &r) const { return key_ >= r.key_; }
  bool operator==(const KV<T, U> &r) const { return key_ == r.key_; }
  static KV<T, U> Max() { return KV(std::numeric_limits<T>::max(), std::numeric_limits<U>::max()); }
 private:
  T key_;
  U value_;
};

using Range = KV<int, std::pair<int, int>>;

int main() {
  int N;
  std::cin >> N;
  RangeMinimum<KV<int, int>> oddSegmentTree(N);
  RangeMinimum<KV<int, int>> evenSegmentTree(N);
  for (int i = 0; i < N; ++i) {
    int p;
    std::cin >> p;
    if (i % 2) { oddSegmentTree.Update(i, KV<int, int>(p, i)); }
    else { evenSegmentTree.Update(i, KV<int, int>(p, i)); }
  }

  std::priority_queue<Range, std::vector<Range>, std::greater<Range>> range;
  range.push(Range(evenSegmentTree.Query(0, N).Key(), std::make_pair(0, N)));
  for (int i = 0; i < N / 2; ++i) {
    auto min_range = range.top();
    range.pop();
    auto min = min_range.Value().first % 2 ? oddSegmentTree.Query(min_range.Value().first,
                                                                  min_range.Value().second)
                                           : evenSegmentTree.Query(min_range.Value().first,
                                                                   min_range.Value().second);
    auto next_min = min_range.Value().first % 2 ? evenSegmentTree.Query(min.Value() + 1,
                                                                        min_range.Value().second)
                                                : oddSegmentTree.Query(min.Value() + 1,
                                                                       min_range.Value().second);
    std::cout << min.Key() << " " << next_min.Key() << " ";

    oddSegmentTree.Update(min.Value(), KV<int, int>(std::numeric_limits<int>::max(), min.Value()));
    evenSegmentTree.Update(min.Value(), KV<int, int>(std::numeric_limits<int>::max(), min.Value()));
    oddSegmentTree.Update(next_min.Value(), KV<int, int>(std::numeric_limits<int>::max(), next_min.Value()));
    evenSegmentTree.Update(next_min.Value(), KV<int, int>(std::numeric_limits<int>::max(), next_min.Value()));

    auto update_range = [&](int begin, int end) {
      if (begin + 1 < end) {
        auto min_updated = begin % 2 ? oddSegmentTree.Query(begin, end)
                                     : evenSegmentTree.Query(begin, end);
        range.push(Range(min_updated.Key(), std::make_pair(begin, end)));
      }
    };
    update_range(min_range.Value().first, min.Value());
    update_range(min.Value() + 1, next_min.Value());
    update_range(next_min.Value() + 1, min_range.Value().second);
  }
  return 0;
}

Measured memory_bytes: 10364