Problem p03641 (C++)

Buggy submission (status: Time Limit Exceeded):
/*
题目要求每次删除P的相邻2个数加入到Q的开头。考虑其逆过程：即在得到Q的情况下，每次删除Q的开头2个数插入到P中相邻两个位置；问题转换成找到一个能够完成构造的Q，最小化其字典序
考虑当前求解P[l ~ r]的字典序最小的Q，贪心找到一个字典序最小的pair(P[x],
P[y])，满足P[l ~ x - 1]有偶数个数、P[y + 1 ~ r]有偶数个数，显然P[x + 1 ~ y -
1]中也有偶数个数 这三个部分是独立的，可以分别求解最小的字典序。用堆维护即可
*/

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;
const int Max_N(200050);

int N, P[Max_N], ST[2][20][Max_N], Log[Max_N];

inline int cmin(int a, int b) { return P[a] < P[b] ? a : b; }

inline int rmq(int c, int l, int r) {
  int k = Log[r - l + 1];
  return cmin(ST[c][k][l], ST[c][k][r - (1 << k) + 1]);
}

struct pil {
  pil(const int &_x = 0, const int &_y = 0) : x(_x), y(_y) {}
  int x, y;
  inline bool operator<(const pil &b) const {
    return P[x] == P[b.x] ? P[y] < P[b.y] : P[x] < P[b.x];
  }
  inline bool operator>(const pil &b) const { return b > *this; }
};

struct node {
  node(const int &_l, const int &_r) {
    l = _l, r = _r;
    int a = rmq(l & 1, l, r - 1);
    v = pil(a, rmq(r & 1, a + 1, r));
  }
  int l, r;
  pil v;
  inline bool operator<(const node &b) const { return v > b.v; }
};

int main() {
  scanf("%d", &N);
  P[0] = 0X3F3F3F3F;
  for (int i = 1; i <= N; ++i)
    scanf("%d", P + i);
  for (int i = 1; i <= N; ++i)
    ST[i & 1][0][i] = i;
  for (int c = 0; c <= 1; ++c)
    for (int j = 1; (1 << j) <= N; ++j)
      for (int i = 1; i + (1 << j) - 1 <= N; ++i)
        ST[c][j][i] = cmin(ST[c][j - 1][i], ST[c][j - 1][i + (1 << (j - 1))]);
  Log[0] = Log[1] = 0;
  for (int i = 2; i <= N; ++i)
    Log[i] = Log[i >> 1] + 1;
  priority_queue<node> Q;
  Q.push(node(1, N));
  while (Q.empty() == false) {
    node t = Q.top();
    Q.pop();
    printf("%d %d ", P[t.v.x], P[t.v.y]);
    if (t.l <= t.v.x - 1)
      Q.push(node(t.l, t.v.x - 1));
    if (t.v.x + 1 <= t.v.y - 1)
      Q.push(node(t.v.x + 1, t.v.y - 1));
    if (t.v.y + 1 <= t.r)
      Q.push(node(t.v.y + 1, t.r));
  }
  return 0;
}

Fixed submission:
/*
题目要求每次删除P的相邻2个数加入到Q的开头。考虑其逆过程：即在得到Q的情况下，每次删除Q的开头2个数插入到P中相邻两个位置；问题转换成找到一个能够完成构造的Q，最小化其字典序
考虑当前求解P[l ~ r]的字典序最小的Q，贪心找到一个字典序最小的pair(P[x],
P[y])，满足P[l ~ x - 1]有偶数个数、P[y + 1 ~ r]有偶数个数，显然P[x + 1 ~ y -
1]中也有偶数个数 这三个部分是独立的，可以分别求解最小的字典序。用堆维护即可
*/

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;
const int Max_N(200050);

int N, P[Max_N], ST[2][20][Max_N], Log[Max_N];

inline int cmin(int a, int b) { return P[a] < P[b] ? a : b; }

inline int rmq(int c, int l, int r) {
  int k = Log[r - l + 1];
  return cmin(ST[c][k][l], ST[c][k][r - (1 << k) + 1]);
}

struct pil {
  pil(const int &_x = 0, const int &_y = 0) : x(_x), y(_y) {}
  int x, y;
  inline bool operator<(const pil &b) const {
    return P[x] == P[b.x] ? P[y] < P[b.y] : P[x] < P[b.x];
  }
  inline bool operator>(const pil &b) const { return b < *this; }
};

struct node {
  node(const int &_l, const int &_r) {
    l = _l, r = _r;
    int a = rmq(l & 1, l, r - 1);
    v = pil(a, rmq(r & 1, a + 1, r));
  }
  int l, r;
  pil v;
  inline bool operator<(const node &b) const { return v > b.v; }
};

int main() {
  scanf("%d", &N);
  P[0] = 0X3F3F3F3F;
  for (int i = 1; i <= N; ++i)
    scanf("%d", P + i);
  for (int i = 1; i <= N; ++i)
    ST[i & 1][0][i] = i;
  for (int c = 0; c <= 1; ++c)
    for (int j = 1; (1 << j) <= N; ++j)
      for (int i = 1; i + (1 << j) - 1 <= N; ++i)
        ST[c][j][i] = cmin(ST[c][j - 1][i], ST[c][j - 1][i + (1 << (j - 1))]);
  Log[0] = Log[1] = 0;
  for (int i = 2; i <= N; ++i)
    Log[i] = Log[i >> 1] + 1;
  priority_queue<node> Q;
  Q.push(node(1, N));
  while (Q.empty() == false) {
    node t = Q.top();
    Q.pop();
    printf("%d %d ", P[t.v.x], P[t.v.y]);
    if (t.l <= t.v.x - 1)
      Q.push(node(t.l, t.v.x - 1));
    if (t.v.x + 1 <= t.v.y - 1)
      Q.push(node(t.v.x + 1, t.v.y - 1));
    if (t.v.y + 1 <= t.r)
      Q.push(node(t.v.y + 1, t.r));
  }
  return 0;
}