Problem p03235 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#define FILL(a, n, x) memset((a), (x), sizeof((a)[0]) * (n))
#define FILLA(a, x) memset((a), (x), sizeof(a))
#define COPY(a, n, b) memcpy((b), (a), sizeof((a)[0]) * (n))
#define COPYA(a, b) memcpy((b), (a), sizeof(a))
using namespace std;

typedef pair<int, int> pii;
typedef long long li;
typedef unsigned long long lu;
const int inf = ~0U >> 2;
const li infl = ~0LLU >> 2;

template <class T> inline void Min(T &x, T y) {
  if (y < x)
    x = y;
}
template <class T> inline void Max(T &x, T y) {
  if (y > x)
    x = y;
}

// ----------------------------------------

const int maxn = 2e5;

struct Data {
  int maxv[2];

  void operator+=(const Data &b) {
    Max(maxv[0], b.maxv[0]);
    Max(maxv[1], b.maxv[1]);
  }

  Data operator+(const Data &b) const {
    return {max(maxv[0], b.maxv[0]), max(maxv[1], b.maxv[1])};
  }
};

int n, P[maxn];
bool old[maxn];

namespace seg {
const int max_node = 2e5 * 19;

struct Node {
  int lc, rc;
  Data dat;
} node[max_node];

int nd;

void Build(int u, int l, int r) {
  if (r - l == 1) {
    node[u] = {-1, -1, {0, -inf}};
  } else {
    node[u] = {nd, nd + 1, {0, -inf}};
    nd += 2;
    int mid = l + r >> 1;
    Build(node[u].lc, l, mid);
    Build(node[u].rc, mid, r);
  }
}

int Init(void) {
  nd = 1;
  Build(0, 0, n);
  return 0;
}

int ql, qr;
Data qx;

void QQuery(int u, int l, int r) {
  if (ql <= l && qr >= r) {
    qx += node[u].dat;
    return;
  }
  int mid = l + r >> 1;
  if (ql < mid)
    QQuery(node[u].lc, l, mid);
  if (qr > mid)
    QQuery(node[u].rc, mid, r);
}

Data Query(int root, int l, int r) {
  if (l >= r)
    return {0, -inf};
  qx = {0, -inf};
  ql = l;
  qr = r;
  QQuery(root, 0, n);
  return qx;
}

void Copy(int &u) {
  int v = nd++;
  node[v] = node[u];
  u = v;
}

void UUpdate(int &u, int l, int r) {
  Copy(u);
  if (r - l == 1) {
    node[u].dat += qx;
    return;
  }
  int mid = l + r >> 1;
  if (ql < mid) {
    UUpdate(node[u].lc, l, mid);
  } else {
    UUpdate(node[u].rc, mid, r);
  }
  node[u].dat = node[node[u].lc].dat + node[node[u].rc].dat;
}

int Update(int root, int i, const Data &x) {
  ql = i;
  qx = x;
  UUpdate(root, 0, n);
  return root;
}
} // namespace seg

int root[maxn + 1];
int dire[maxn];
int tail[2];

int suf_old[maxn + 1];

bool Check(int i, int prev, int tail) {
  prev += suf_old[i];
  if (prev < 0)
    return false;
  int tar = prev;
  Data res = seg::Query(root[i], tail, n);
  // printf("Check(%d, %d, %d) = %d %d\n", i, prev, tail,
  //        res.maxv[0], res.maxv[1]);
  return res.maxv[tar & 1] >= tar;
}

int main(void) {
  scanf("%d", &n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", P + i);
    --P[i];
  }
  int maxv = -1;
  FILL(old, n, 0);
  for (int i = 0; i < n; ++i) {
    if (P[i] > maxv) {
      maxv = P[i];
      old[i] = true;
    }
  }

  suf_old[n] = 0;
  for (int i = n - 1; i >= 0; --i) {
    suf_old[i] = suf_old[i + 1] + old[i];
  }

  root[n] = seg::Init();
  for (int i = n - 1; i >= 0; --i) {
    Data res = seg::Query(root[i + 1], P[i], n);
    Data now;
    if (old[i]) {
      now = (Data){res.maxv[0] + 2, res.maxv[1] + 2};
    } else {
      now = (Data){res.maxv[1] + 1, res.maxv[0] + 1};
    }
    root[i] = seg::Update(root[i + 1], P[i], now);
  }

  if (!Check(0, 0, 0)) {
    puts("-1");
    return 0;
  }

  tail[0] = tail[1] = -1;
  int lambda = 0;
  for (int i = 0; i < n; ++i) {
    // Try 0
    int tail_0 = tail[0];
    int lambda_0 = lambda;
    if (P[i] > tail[0]) {
      tail[0] = P[i];
      ++lambda;
    }
    if (Check(i + 1, lambda, tail[1]) || Check(i + 1, -lambda, tail[0])) {
      dire[i] = 0;
      continue;
    }
    lambda = lambda_0;
    tail[0] = tail_0;

    // Set 1
    if (P[i] > tail[1]) {
      tail[1] = P[i];
      --lambda;
    }
    dire[i] = 1;
  }

  for (int i = 0; i < n; ++i) {
    putchar('0' + dire[i]);
  }
  putchar('\n');
  return 0;
}


Fixed submission:
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#define FILL(a, n, x) memset((a), (x), sizeof((a)[0]) * (n))
#define FILLA(a, x) memset((a), (x), sizeof(a))
#define COPY(a, n, b) memcpy((b), (a), sizeof((a)[0]) * (n))
#define COPYA(a, b) memcpy((b), (a), sizeof(a))
using namespace std;

typedef pair<int, int> pii;
typedef long long li;
typedef unsigned long long lu;
const int inf = ~0U >> 2;
const li infl = ~0LLU >> 2;

template <class T> inline void Min(T &x, T y) {
  if (y < x)
    x = y;
}
template <class T> inline void Max(T &x, T y) {
  if (y > x)
    x = y;
}

// ----------------------------------------

const int maxn = 2e5;

struct Data {
  int maxv[2];

  void operator+=(const Data &b) {
    Max(maxv[0], b.maxv[0]);
    Max(maxv[1], b.maxv[1]);
  }

  Data operator+(const Data &b) const {
    return {max(maxv[0], b.maxv[0]), max(maxv[1], b.maxv[1])};
  }
};

int n, P[maxn];
bool old[maxn];

namespace seg {
const int max_node = 4e5 + 2e5 * 19;

struct Node {
  int lc, rc;
  Data dat;
} node[max_node];

int nd;

void Build(int u, int l, int r) {
  if (r - l == 1) {
    node[u] = {-1, -1, {0, -inf}};
  } else {
    node[u] = {nd, nd + 1, {0, -inf}};
    nd += 2;
    int mid = l + r >> 1;
    Build(node[u].lc, l, mid);
    Build(node[u].rc, mid, r);
  }
}

int Init(void) {
  nd = 1;
  Build(0, 0, n);
  return 0;
}

int ql, qr;
Data qx;

void QQuery(int u, int l, int r) {
  if (ql <= l && qr >= r) {
    qx += node[u].dat;
    return;
  }
  int mid = l + r >> 1;
  if (ql < mid)
    QQuery(node[u].lc, l, mid);
  if (qr > mid)
    QQuery(node[u].rc, mid, r);
}

Data Query(int root, int l, int r) {
  if (l >= r)
    return {0, -inf};
  qx = {0, -inf};
  ql = l;
  qr = r;
  QQuery(root, 0, n);
  return qx;
}

void Copy(int &u) {
  int v = nd++;
  node[v] = node[u];
  u = v;
}

void UUpdate(int &u, int l, int r) {
  Copy(u);
  if (r - l == 1) {
    node[u].dat += qx;
    return;
  }
  int mid = l + r >> 1;
  if (ql < mid) {
    UUpdate(node[u].lc, l, mid);
  } else {
    UUpdate(node[u].rc, mid, r);
  }
  node[u].dat = node[node[u].lc].dat + node[node[u].rc].dat;
}

int Update(int root, int i, const Data &x) {
  ql = i;
  qx = x;
  UUpdate(root, 0, n);
  return root;
}
} // namespace seg

int root[maxn + 1];
int dire[maxn];
int tail[2];

int suf_old[maxn + 1];

bool Check(int i, int prev, int tail) {
  prev += suf_old[i];
  if (prev < 0)
    return false;
  int tar = prev;
  Data res = seg::Query(root[i], tail, n);
  // printf("Check(%d, %d, %d) = %d %d\n", i, prev, tail,
  //        res.maxv[0], res.maxv[1]);
  return res.maxv[tar & 1] >= tar;
}

int main(void) {
  scanf("%d", &n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", P + i);
    --P[i];
  }
  int maxv = -1;
  FILL(old, n, 0);
  for (int i = 0; i < n; ++i) {
    if (P[i] > maxv) {
      maxv = P[i];
      old[i] = true;
    }
  }

  suf_old[n] = 0;
  for (int i = n - 1; i >= 0; --i) {
    suf_old[i] = suf_old[i + 1] + old[i];
  }

  root[n] = seg::Init();
  for (int i = n - 1; i >= 0; --i) {
    Data res = seg::Query(root[i + 1], P[i], n);
    Data now;
    if (old[i]) {
      now = (Data){res.maxv[0] + 2, res.maxv[1] + 2};
    } else {
      now = (Data){res.maxv[1] + 1, res.maxv[0] + 1};
    }
    root[i] = seg::Update(root[i + 1], P[i], now);
  }

  if (!Check(0, 0, 0)) {
    puts("-1");
    return 0;
  }

  tail[0] = tail[1] = -1;
  int lambda = 0;
  for (int i = 0; i < n; ++i) {
    // Try 0
    int tail_0 = tail[0];
    int lambda_0 = lambda;
    if (P[i] > tail[0]) {
      tail[0] = P[i];
      ++lambda;
    }
    if (Check(i + 1, lambda, tail[1]) || Check(i + 1, -lambda, tail[0])) {
      dire[i] = 0;
      continue;
    }
    lambda = lambda_0;
    tail[0] = tail_0;

    // Set 1
    if (P[i] > tail[1]) {
      tail[1] = P[i];
      --lambda;
    }
    dire[i] = 1;
  }

  for (int i = 0; i < n; ++i) {
    putchar('0' + dire[i]);
  }
  putchar('\n');
  return 0;
}