Problem p03641 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

#define MOD 1000000007
#define INF 1000000000
#define MAX_N 100005

int n;                              // 葉の数。2 のべき乗
pair<int, int> even[MAX_N * 2 - 1]; // 偶数番目の要素のセグメント木 (位置, 値)
pair<int, int> odd[MAX_N * 2 - 1]; // 奇数番目の要素のセグメント木 (位置, 値)
// セグメント木での Range Minimum Query (RMQ) の実装
// 区間[i, j] に含まれる最小値の取得と、値の更新
// 初期化
void init() {
  REP(i, 2 * n - 1) {
    even[i].first = i;
    even[i].second = INF;
    odd[i].first = i;
    odd[i].first = INF;
  }
}
// 値の更新 O(log n)
// i 番目の値 (0-indexed) を x に変更
void update(bool isEven, int i, pair<int, int> x) {
  // 葉の番号
  i += n - 1;
  if (isEven) {
    even[i] = x;
    // printf("update even[%d] to (%d, %d)\n", i, even[i].first,
    // even[i].second);
  } else {
    odd[i] = x;
    // printf("update odd[%d] to (%d, %d)\n", i, odd[i].first, odd[i].second);
  }
  // 登りながら更新
  while (i > 0) {
    i = (i - 1) / 2;
    if (isEven) {
      if (even[i * 2 + 1].second < even[i * 2 + 2].second) {
        even[i] = even[i * 2 + 1];
      } else {
        even[i] = even[i * 2 + 2];
      }
    } else {
      if (odd[i * 2 + 1].second < odd[i * 2 + 2].second) {
        odd[i] = odd[i * 2 + 1];
      } else {
        odd[i] = odd[i * 2 + 2];
      }
    }
  }
}
// 最小値の取得 O(log n)
// [a, b) の最小値、 l, r にはノード k に対応づく区間を与える
// 一番初めは query_impl(a, b, 0, 0, n) のように呼ぶ
pair<int, int> query_impl(bool isEven, int a, int b, int k, int l, int r) {
  if (r <= a || b <= l) {
    return make_pair(INF, INF);
  } // 交差しない？
  if (a <= l && r <= b) {
    if (isEven) {
      return even[k];
    } else {
      return odd[k];
    }
  } // 完全に含む？
  else {
    pair<int, int> vl =
        query_impl(isEven, a, b, k * 2 + 1, l, (l + r) / 2); // 左の子を見る
    pair<int, int> vr =
        query_impl(isEven, a, b, k * 2 + 2, (l + r) / 2, r); // 右の子を見る
    // printf("  vl.second %d vr.second %d\n", vl.second, vr.second);
    if (vl.second < vr.second) {
      return vl;
    } else {
      return vr;
    }
  }
}
pair<int, int> query(bool isEven, int a, int b) {
  return query_impl(isEven, a, b, 0, 0, n);
}

int ans[MAX_N * 4];
int N;

// 2 のべき乗かどうか
int isPow(int num) {
  int res = 2;
  while (res < num) {
    res *= 2;
  }
  if (res == num) {
    return 0;
  } else {
    return res - num;
  }
}

int main() {
  ZERO(ans);
  cin >> N;
  n = N / 2;
  int ret = isPow(n);
  if (ret != 0) {
    n += ret;
  }
  // セグメント木の構築
  init();
  REP(i, N) {
    int tmp;
    // scanf("%d", &tmp);
    cin >> tmp;
    bool isEven = (i % 2 == 0);
    // printf("add ind %d (%d, %d) to %s\n", i / 2, i, tmp, (isEven) ? "even" :
    // "odd");
    update(isEven, i / 2, make_pair(i, tmp));
  }

  // 区間 (区間の最小値, 区間の範囲 [) )
  priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>,
                 greater<pair<int, pair<int, int>>>>
      range;
  range.push(make_pair(query(true, 0, n).second, make_pair(0, N)));
  // printf("min: %d\n", query(true, 0, n).second);
  // printf("min: %d\n", query(false, 0, n).second);
  // REP(i, 2*n-1) {
  //     printf("%d ", even[i].second);
  // }
  // printf("\n");
  // printf("test: %d\n", query(true, 0, 2).second);

  int ans_ind = 0;
  while (ans_ind < N) {
    // 最小の値を持つ区間を取得
    pair<int, pair<int, int>> min_range = range.top();
    range.pop();
    bool isEven = (min_range.second.first % 2 == 0); // 区間の始点は偶数か？
    // 確定した値を入れる
    pair<int, int> cand1, cand2;
    // printf("min_range.second (%d, %d)\n", min_range.second.first,
    // min_range.second.second);
    cand1 =
        query(isEven, min_range.second.first / 2, min_range.second.second / 2);
    if (isEven) {
      // cand2 では奇数を見る
      cand2 = query(false, cand1.first / 2, min_range.second.second / 2);
    } else {
      // cand2 では偶数を見る
      cand2 = query(true, cand1.first / 2 + 1, min_range.second.second / 2 + 1);
    }
    // printf("get (%d, %d) (%d, %d)\n", cand1.first, cand1.second, cand2.first,
    // cand2.second);
    ans[ans_ind] = cand1.second;
    ans_ind++;
    ans[ans_ind] = cand2.second;
    ans_ind++;
    if (ans_ind >= N) {
      break;
    }
    // 区間を 3 つに分割
    pair<int, int> range1 = make_pair(min_range.second.first, cand1.first);
    pair<int, int> range2 = make_pair(cand1.first + 1, cand2.first);
    pair<int, int> range3 = make_pair(cand2.first + 1, min_range.second.second);
    // 各区間を priority_queue に入れる
    if (range1.first != range1.second) {
      isEven = (range1.first % 2 == 0);
      pair<int, int> min_range1 =
          query(isEven, range1.first / 2, range1.second / 2);
      assert(min_range1.first >= range1.first);
      assert(min_range1.first <= range1.second);
      range.push(make_pair(min_range1.second, range1));
      // printf("1add %d [%d, %d)\n", min_range1, range1.first, range1.second);
    }
    if (range2.first != range2.second) {
      isEven = (range2.first % 2 == 0);
      int min_range2 =
          query(isEven, range2.first / 2, range2.second / 2).second;
      range.push(make_pair(min_range2, range2));
      // printf("2add %d [%d, %d)\n", min_range2, range2.first, range2.second);
    }
    if (range3.first != range3.second) {
      isEven = (range3.first % 2 == 0);
      int min_range3 =
          query(isEven, range3.first / 2, range3.second / 2).second;
      range.push(make_pair(min_range3, range3));
      // printf("3add %d [%d, %d)\n", min_range3, range3.first, range3.second);
    }
    // printf("\n");
  }
  // assert(range.size() == 0);
  REP(i, N) {
    printf("%d", ans[i]);
    if (i != N - 1) {
      printf(" ");
    }
  }
  printf("\n");
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

#define MOD 1000000007
#define INF 1000000000
#define MAX_N 200005

int n;                              // 葉の数。2 のべき乗
pair<int, int> even[MAX_N * 2 - 1]; // 偶数番目の要素のセグメント木 (位置, 値)
pair<int, int> odd[MAX_N * 2 - 1]; // 奇数番目の要素のセグメント木 (位置, 値)
// セグメント木での Range Minimum Query (RMQ) の実装
// 区間[i, j] に含まれる最小値の取得と、値の更新
// 初期化
void init() {
  REP(i, 2 * n - 1) {
    even[i].first = i;
    even[i].second = INF;
    odd[i].first = i;
    odd[i].first = INF;
  }
}
// 値の更新 O(log n)
// i 番目の値 (0-indexed) を x に変更
void update(bool isEven, int i, pair<int, int> x) {
  // 葉の番号
  i += n - 1;
  if (isEven) {
    even[i] = x;
    // printf("update even[%d] to (%d, %d)\n", i, even[i].first,
    // even[i].second);
  } else {
    odd[i] = x;
    // printf("update odd[%d] to (%d, %d)\n", i, odd[i].first, odd[i].second);
  }
  // 登りながら更新
  while (i > 0) {
    i = (i - 1) / 2;
    if (isEven) {
      if (even[i * 2 + 1].second < even[i * 2 + 2].second) {
        even[i] = even[i * 2 + 1];
      } else {
        even[i] = even[i * 2 + 2];
      }
    } else {
      if (odd[i * 2 + 1].second < odd[i * 2 + 2].second) {
        odd[i] = odd[i * 2 + 1];
      } else {
        odd[i] = odd[i * 2 + 2];
      }
    }
  }
}
// 最小値の取得 O(log n)
// [a, b) の最小値、 l, r にはノード k に対応づく区間を与える
// 一番初めは query_impl(a, b, 0, 0, n) のように呼ぶ
pair<int, int> query_impl(bool isEven, int a, int b, int k, int l, int r) {
  if (r <= a || b <= l) {
    return make_pair(INF, INF);
  } // 交差しない？
  if (a <= l && r <= b) {
    if (isEven) {
      return even[k];
    } else {
      return odd[k];
    }
  } // 完全に含む？
  else {
    pair<int, int> vl =
        query_impl(isEven, a, b, k * 2 + 1, l, (l + r) / 2); // 左の子を見る
    pair<int, int> vr =
        query_impl(isEven, a, b, k * 2 + 2, (l + r) / 2, r); // 右の子を見る
    // printf("  vl.second %d vr.second %d\n", vl.second, vr.second);
    if (vl.second < vr.second) {
      return vl;
    } else {
      return vr;
    }
  }
}
pair<int, int> query(bool isEven, int a, int b) {
  return query_impl(isEven, a, b, 0, 0, n);
}

int ans[MAX_N * 4];
int N;

// 2 のべき乗かどうか
int isPow(int num) {
  int res = 2;
  while (res < num) {
    res *= 2;
  }
  if (res == num) {
    return 0;
  } else {
    return res - num;
  }
}

int main() {
  ZERO(ans);
  cin >> N;
  n = N / 2;
  int ret = isPow(n);
  if (ret != 0) {
    n += ret;
  }
  // セグメント木の構築
  init();
  REP(i, N) {
    int tmp;
    // scanf("%d", &tmp);
    cin >> tmp;
    bool isEven = (i % 2 == 0);
    // printf("add ind %d (%d, %d) to %s\n", i / 2, i, tmp, (isEven) ? "even" :
    // "odd");
    update(isEven, i / 2, make_pair(i, tmp));
  }

  // 区間 (区間の最小値, 区間の範囲 [) )
  priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>,
                 greater<pair<int, pair<int, int>>>>
      range;
  range.push(make_pair(query(true, 0, n).second, make_pair(0, N)));
  // printf("min: %d\n", query(true, 0, n).second);
  // printf("min: %d\n", query(false, 0, n).second);
  // REP(i, 2*n-1) {
  //     printf("%d ", even[i].second);
  // }
  // printf("\n");
  // printf("test: %d\n", query(true, 0, 2).second);

  int ans_ind = 0;
  while (ans_ind < N) {
    // 最小の値を持つ区間を取得
    pair<int, pair<int, int>> min_range = range.top();
    range.pop();
    bool isEven = (min_range.second.first % 2 == 0); // 区間の始点は偶数か？
    // 確定した値を入れる
    pair<int, int> cand1, cand2;
    // printf("min_range.second (%d, %d)\n", min_range.second.first,
    // min_range.second.second);
    cand1 =
        query(isEven, min_range.second.first / 2, min_range.second.second / 2);
    if (isEven) {
      // cand2 では奇数を見る
      cand2 = query(false, cand1.first / 2, min_range.second.second / 2);
    } else {
      // cand2 では偶数を見る
      cand2 = query(true, cand1.first / 2 + 1, min_range.second.second / 2 + 1);
    }
    // printf("get (%d, %d) (%d, %d)\n", cand1.first, cand1.second, cand2.first,
    // cand2.second);
    ans[ans_ind] = cand1.second;
    ans_ind++;
    ans[ans_ind] = cand2.second;
    ans_ind++;
    if (ans_ind >= N) {
      break;
    }
    // 区間を 3 つに分割
    pair<int, int> range1 = make_pair(min_range.second.first, cand1.first);
    pair<int, int> range2 = make_pair(cand1.first + 1, cand2.first);
    pair<int, int> range3 = make_pair(cand2.first + 1, min_range.second.second);
    // 各区間を priority_queue に入れる
    if (range1.first != range1.second) {
      isEven = (range1.first % 2 == 0);
      pair<int, int> min_range1 =
          query(isEven, range1.first / 2, range1.second / 2);
      assert(min_range1.first >= range1.first);
      assert(min_range1.first <= range1.second);
      range.push(make_pair(min_range1.second, range1));
      // printf("1add %d [%d, %d)\n", min_range1, range1.first, range1.second);
    }
    if (range2.first != range2.second) {
      isEven = (range2.first % 2 == 0);
      int min_range2 =
          query(isEven, range2.first / 2, range2.second / 2).second;
      range.push(make_pair(min_range2, range2));
      // printf("2add %d [%d, %d)\n", min_range2, range2.first, range2.second);
    }
    if (range3.first != range3.second) {
      isEven = (range3.first % 2 == 0);
      int min_range3 =
          query(isEven, range3.first / 2, range3.second / 2).second;
      range.push(make_pair(min_range3, range3));
      // printf("3add %d [%d, %d)\n", min_range3, range3.first, range3.second);
    }
    // printf("\n");
  }
  // assert(range.size() == 0);
  REP(i, N) {
    printf("%d", ans[i]);
    if (i != N - 1) {
      printf(" ");
    }
  }
  printf("\n");
  return 0;
}