Problem p02551 (C++) — buggy submission, verdict: Runtime Error

#include <bits/stdc++.h>

using namespace std;
using int64 = long long;

constexpr int DEBUG = 0;

template <typename T> class SegmentTree {
private:
  function<T(T, T)> merge_fn;
  T empty_value;
  vector<T> nodes;
  int num_nodes;

  // Returns the fold of overwrap between [node_l, node_r) and [l, r).
  // nodes[node_index] needs to correspond to [node_l, node_r).
  T GetRangeInternal(int node_index, int node_l, int node_r, int l, int r) {
    if (node_r <= l || r <= node_l)
      return empty_value;
    if (l <= node_l && node_r <= r)
      return nodes[node_index];
    int node_m = (node_l + node_r) / 2;
    return merge_fn(GetRangeInternal(2 * node_index, node_l, node_m, l, r),
                    GetRangeInternal(2 * node_index + 1, node_m, node_r, l, r));
  }

public:
  // Arguments:
  // in_merge: The function to merge two values. It should be a monoid.
  // in_empty_value: The identity of the monoid.
  // xs: The initial values.
  SegmentTree(function<T(T, T)> merge_fn, T empty_value, const vector<T> &xs)
      : merge_fn(merge_fn), empty_value(empty_value) {
    int n = xs.size();
    num_nodes = 1;
    while (num_nodes < n)
      num_nodes *= 2;
    num_nodes *= 2;
    nodes = vector<T>(num_nodes, empty_value);
    for (int i = 0; i < xs.size(); ++i) {
      nodes[num_nodes / 2 + i] = xs[i];
    }
    for (int i = num_nodes / 2 - 1; i >= 1; i--) {
      nodes[i] = merge_fn(nodes[2 * i], nodes[2 * i + 1]);
    }
  }

  // Updates the i-th element to x.
  void Update(int i, T x) {
    nodes[num_nodes / 2 + i] = x;
    for (int cur = (num_nodes / 2 + i) / 2; cur > 0; cur /= 2) {
      nodes[cur] = merge_fn(nodes[2 * cur], nodes[2 * cur + 1]);
    }
  }

  // Returns the value of the range [l, r) merged by merge_fn.
  T GetRange(int l, int r) {
    return GetRangeInternal(1, 0, num_nodes / 2, l, r);
  }

  T Get(int i) { return nodes[num_nodes / 2 + i]; }
};

// Constraints:
// - is_upper_fn(l) = false.
// - is_upper_fn(u) = true.
// - is_upper_fn() is monotically increasing.
tuple<int, int> BinarySearch(int l, int u, function<bool(int)> is_upper_fn) {
  while (u - l >= 2) {
    int m = (l + u) / 2;
    if (is_upper_fn(m)) {
      u = m;
    } else {
      l = m;
    }
  }
  return {l, u};
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  function<int(int, int)> max_fn = [](int x, int y) { return max(x, y); };

  int n, q;
  cin >> n >> q;

  int64 ans = 0;

  SegmentTree<int> r_tree(max_fn, 0, vector<int>(n - 2, 0));
  SegmentTree<int> c_tree(max_fn, 0, vector<int>(n - 2, 0));
  for (int q_index = 0; q_index < q; q_index++) {
    int t;
    int x;
    cin >> t >> x;
    x -= 2;

    auto process_r_fn = [&] {
      int r = x;
      // if (c_tree.Get(0) >= r + 1) {
      //   return;
      // }
      if (c_tree.GetRange(0, n - 2) <= r) {
        ans += n - 2;
        r_tree.Update(r, n - 2);
        return;
      }

      auto is_upper_fn = [&](int c) -> bool {
        return c_tree.GetRange(0, c) >= r + 1;
      };
      int l = 0;
      int u = n - 2;
      // for (int i = l; i <= u; i++) {
      //   cout << c_tree.GetRange(0, i) << " " << is_upper_fn(i) << endl;
      // }
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      // cout << "l: " << l << " u: " << u << endl;
      ans += l;
      r_tree.Update(r, l);
    };

    auto process_c_fn = [&] {
      int c = x;
      // if (r_tree.Get(0) >= c + 1) {
      //   return;
      // }
      if (r_tree.GetRange(0, n - 2) <= c) {
        ans += n - 2;
        c_tree.Update(c, n - 2);
        return;
      }

      auto is_upper_fn = [&](int r) -> bool {
        return r_tree.GetRange(0, r) >= c + 1;
      };
      int l = 0;
      int u = n - 2;
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      ans += l;
      c_tree.Update(c, l);
    };

    if (t == 1) {
      process_c_fn();
    } else {
      process_r_fn();
    }

    // cout << "q_index: " << q_index << " " << ans << endl;
    // cout << "r_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << r_tree.Get(i) << " ";
    // }
    // cout << endl;
    // cout << "c_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << c_tree.Get(i) << " ";
    // }
    // cout << endl;
    // cout << endl;
  }

  // cout << ans << endl;
  cout << static_cast<int64>(n - 2) * (n - 2) - ans << endl;
}

Error: WA

Fixed submission:

#include <bits/stdc++.h>

using namespace std;
using int64 = long long;

constexpr int DEBUG = 0;

template <typename T> class SegmentTree {
private:
  function<T(T, T)> merge_fn;
  T empty_value;
  vector<T> nodes;
  int num_nodes;

  // Returns the fold of overwrap between [node_l, node_r) and [l, r).
  // nodes[node_index] needs to correspond to [node_l, node_r).
  T GetRangeInternal(int node_index, int node_l, int node_r, int l, int r) {
    if (node_r <= l || r <= node_l)
      return empty_value;
    if (l <= node_l && node_r <= r)
      return nodes[node_index];
    int node_m = (node_l + node_r) / 2;
    return merge_fn(GetRangeInternal(2 * node_index, node_l, node_m, l, r),
                    GetRangeInternal(2 * node_index + 1, node_m, node_r, l, r));
  }

public:
  // Arguments:
  // in_merge: The function to merge two values. It should be a monoid.
  // in_empty_value: The identity of the monoid.
  // xs: The initial values.
  SegmentTree(function<T(T, T)> merge_fn, T empty_value, const vector<T> &xs)
      : merge_fn(merge_fn), empty_value(empty_value) {
    int n = xs.size();
    num_nodes = 1;
    while (num_nodes < n)
      num_nodes *= 2;
    num_nodes *= 2;
    nodes = vector<T>(num_nodes, empty_value);
    for (int i = 0; i < xs.size(); ++i) {
      nodes[num_nodes / 2 + i] = xs[i];
    }
    for (int i = num_nodes / 2 - 1; i >= 1; i--) {
      nodes[i] = merge_fn(nodes[2 * i], nodes[2 * i + 1]);
    }
  }

  // Updates the i-th element to x.
  void Update(int i, T x) {
    nodes[num_nodes / 2 + i] = x;
    for (int cur = (num_nodes / 2 + i) / 2; cur > 0; cur /= 2) {
      nodes[cur] = merge_fn(nodes[2 * cur], nodes[2 * cur + 1]);
    }
  }

  // Returns the value of the range [l, r) merged by merge_fn.
  T GetRange(int l, int r) {
    return GetRangeInternal(1, 0, num_nodes / 2, l, r);
  }

  T Get(int i) { return nodes[num_nodes / 2 + i]; }
};

// Constraints:
// - is_upper_fn(l) = false.
// - is_upper_fn(u) = true.
// - is_upper_fn() is monotically increasing.
tuple<int, int> BinarySearch(int l, int u, function<bool(int)> is_upper_fn) {
  while (u - l >= 2) {
    int m = (l + u) / 2;
    if (is_upper_fn(m)) {
      u = m;
    } else {
      l = m;
    }
  }
  return {l, u};
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  function<int(int, int)> max_fn = [](int x, int y) { return max(x, y); };

  int n, q;
  cin >> n >> q;

  int64 ans = 0;

  SegmentTree<int> r_tree(max_fn, 0, vector<int>(n - 2, 0));
  SegmentTree<int> c_tree(max_fn, 0, vector<int>(n - 2, 0));
  for (int q_index = 0; q_index < q; q_index++) {
    int t;
    int x;
    cin >> t >> x;
    x -= 2;

    auto process_r_fn = [&] {
      int r = x;
      if (c_tree.Get(0) >= r + 1) {
        return;
      }
      if (c_tree.GetRange(0, n - 2 + 1) <= r) {
        ans += n - 2;
        r_tree.Update(r, n - 2);
        return;
      }

      auto is_upper_fn = [&](int c) -> bool {
        c_tree.GetRange(0, c + 1) >= r + 1;
      };
      int l = 0;
      int u = n - 2;
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      ans += l + 1;
      r_tree.Update(r, l + 1);
    };

    auto process_c_fn = [&] {
      int c = x;
      if (r_tree.Get(0) >= c + 1) {
        return;
      }
      if (r_tree.GetRange(0, n - 2 + 1) <= c) {
        ans += n - 2;
        c_tree.Update(c, n - 2);
        return;
      }

      auto is_upper_fn = [&](int r) -> bool {
        r_tree.GetRange(0, r + 1) >= c + 1;
      };
      int l = 0;
      int u = n - 2;
      tie(l, u) = BinarySearch(l, u, is_upper_fn);
      ans += l + 1;
      c_tree.Update(c, l + 1);
    };

    if (t == 1) {
      process_c_fn();
    } else {
      process_r_fn();
    }

    // cout << "q_index: " << q_index << " " << ans << endl;
    // cout << "r_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << r_tree.Get(i) << " ";
    // }
    // cout << endl;
    // cout << "c_tree: ";
    // for (int i = 0; i < n - 2; i++) {
    //   cout << c_tree.Get(i) << " ";
    // }
    // cout << endl;
  }

  cout << ans << endl;
  cout << static_cast<int64>(n - 2) * (n - 2) - ans << endl;
}