Problem p02580 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < (n); ++i)
#define FOR(i, a, b)                                                           \\
  for (long long i = (a); ((a) < (b) ? i <= (b) : i >= (b));                   \\
       ((a) < (b) ? ++i : --i))
#define SZ(v) ((int)(v).size())
#define ALL(v) (v).begin(), (v).end()
#define debug(x) cerr << #x << ": " << (x) << endl
using namespace std;
using llong = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using pii = pair<int, int>;
constexpr int INF = 1e9;
constexpr double EPS = 1e-9;
constexpr int MOD = 1e9 + 7;
template <class Type> void line(const Type &a) {
  int cnt = 0;
  for (const auto &elem : a) {
    cerr << (cnt++ ? ' ' : '>');
    cerr << elem;
  }
  cerr << endl;
}

int main() { // Refering other editorials.
  int h, w;
  int m;
  cin >> h >> w >> m;

  set<pii> st;              // 爆破予定場所の集合.
  vi cnt(h, 0), cntt(w, 0); // それぞれのx,y軸上にある爆破予定場所の数.
  REP(i, m) {
    int y, x;
    cin >> y >> x;
    y--, x--;

    st.insert(pii(y, x));
    cnt[y]++;
    cntt[x]++;
  }

  vi py, px;            // 爆破座標候補.
  int mxy = 0, mxx = 0; // それぞれの最大値.
  REP(i, h) {
    if (cnt[i] == mxy)
      py.push_back(i);
    else if (cnt[i] > mxy) {
      py = vi({i});
      mxy = cnt[i];
    }
  }
  REP(i, w) {
    if (cntt[i] == mxx)
      px.push_back(i);
    else if (cntt[i] > mxx) {
      px = vi({i});
      mxx = cntt[i];
    }
  }

  bool jud = false; // 最大候補の行と列が重なるとこに候補地がないかどうか.
  for (auto i : py)
    for (auto j : px) {
      if (st.find(pii(i, j)) == st.end()) {
        jud = true;
        goto Exit;
      }
    }

Exit:
  cout << mxy + mxx - (jud ? 0 : 1) << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < (n); ++i)
#define FOR(i, a, b)                                                           \\
  for (long long i = (a); ((a) < (b) ? i <= (b) : i >= (b));                   \\
       ((a) < (b) ? ++i : --i))
#define SZ(v) ((int)(v).size())
#define ALL(v) (v).begin(), (v).end()
#define debug(x) cerr << #x << ": " << (x) << endl
using namespace std;
using llong = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using pii = pair<int, int>;
constexpr int INF = 1e9;
constexpr double EPS = 1e-9;
constexpr int MOD = 1e9 + 7;
template <class Type> void line(const Type &a) {
  int cnt = 0;
  for (const auto &elem : a) {
    cerr << (cnt++ ? ' ' : '>');
    cerr << elem;
  }
  cerr << endl;
}

template <class Type_a, class Type_b>
inline bool chmax(Type_a &a, const Type_b &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class Type_a, class Type_b>
inline bool chmin(Type_a &a, const Type_b &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template <typename Type, class Func = function<Type(Type, Type)>>
class SegmentTree {
  int n, offset; // n:=(葉の数（2の階乗数)),offset:=(オフセット(n-1)).
  const Type e; // e:=(単位元).
  vector<Type> node;
  const Func f; // f:=(二項演算処理).

  int bufsize(int n_) { // bufsize:=(木の必要なノード数を返す).
    n = 1;
    while (n < n_)
      n <<= 1;
    offset = n - 1;
    return 2 * n - 1;
  }
  void build(int l = 0, int r = -1) { // build:=(木を構築). O(N).
    if (r < 0)
      r = n;
    l += offset, r += offset;
    do {
      l = (l - 1) / 2, r = (r - 1) / 2;
      for (int i = l; i < r; ++i)
        node[i] = f(node[2 * i + 1], node[2 * i + 2]);
    } while (l > 0);
  }

public:
  /*Constructor.*/
  SegmentTree(int n_, Type e_, Func f_) : node(bufsize(n_), e_), e(e_), f(f_) {}
  SegmentTree(vector<Type> &v_, Type e_, Func f_)
      : node(bufsize(v_.size()), e_), e(e_), f(f_) {
    copy(ALL(v_), node.begin() + offset); //<algorithm>
    build();
  }

  void init() { fill(ALL(node), e); } // init:=(初期化).
  void update(int k, Type a) { // update:=(k番目の要素をaに更新). O(log N).
    k += offset;
    node[k] = a;
    while (k > 0) {
      k = (k - 1) / 2; // parent.
      node[k] = f(node[2 * k + 1], node[2 * k + 2]);
    }
  }
  /*query:=([a,b)間のクエリ結果を返す). O(log N).
  後ろの3つの引数は計算の簡単のための引数.
  kはノード番号,lとrはそのノードが[l,r)に対応づいているかを表す.
  外からはquery(a,b,0,0,n)と呼ぶ.*/
  Type query(int a, int b, int k = 0, int l = 0, int r = -1) {
    if (r < 0)
      r = n;
    if (b <= l or r <= a)
      return e; //[a,b)と[l,r)が交差しなければe.
    if (a <= l and r <= b)
      return node[k]; //[a,b)が[l,r)を完全に含んでいれば,この節点の値.
    Type vl = query(a, b, 2 * k + 1, l, (l + r) / 2);
    Type vr = query(a, b, 2 * k + 2, (l + r) / 2, r);
    return f(vl, vr); // 交差する場合,2つの子をクエリ処理して比較.
  }

  typename vector<Type>::reference operator[](int i) {
    return node[i + offset];
  }
};

int main() {
  int h, w;
  int m;
  cin >> h >> w >> m;

  vector<set<int>> bomb(h); // bomb[y]:=(y座標上にあるbombのx座標の集合).
  vi num(w, 0);             // num[x]:=(x座標上にあるbombの数).
  REP(i, m) {
    int y, x;
    cin >> y >> x;
    y--, x--;

    bomb[y].insert(x);
    num[x]++;
  }

  int ans = -INF;
  REP(i, h) {
    using Type = int;
    auto f = [](Type a, Type b) -> Type { return max(a, b); };
    SegmentTree<Type> tree(num, 0, f);

    // line(bomb[i]);
    for (auto elem : bomb[i]) {
      if (tree[elem] > 0)
        tree.update(elem, tree[elem] - 1);
    }

    chmax(ans, SZ(bomb[i]) + tree.query(0, w));
    // debug(bomb[i].size()+tree.query(0,w));
  }

  cout << ans << endl;
  return 0;
}