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

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = 1; i <= (n); ++i)
#define drep(i, n) for (int i = (n)-1; i >= 0; --i)
#define srep(i, s, t) for (int i = s; i < t; ++i)
using namespace std;
typedef pair<int, int> P;
typedef long long int ll;
#define dame                                                                   \\
  {                                                                            \\
    puts("-1");                                                                \\
    return 0;                                                                  \\
  }
#define yn                                                                     \\
  { puts("Yes"); }                                                             \\
  else {                                                                       \\
    puts("No");                                                                \\
  }

const int MAX_N = 1 << 20;

// セグメント木を持つグローバル配列
int nn, dat[2 * MAX_N - 1];

// 初期化
void init(int n_) {
  // n_が小さいときの変な挙動を防ぐ
  if (n_ < 10)
    n_ = 10;
  // 簡単のため要素数を2のべき乗に
  nn = 1;
  while (nn < n_)
    nn *= 2;

  // 全ての値をINT_MAXに
  for (int i = 0; i < 2 * nn - 1; i++)
    dat[i] = INT_MAX;
}

// k番目の値(0-indexed)をaに変更
void update(int k, int a) {
  // 葉の接点
  k += nn - 1;
  dat[k] = a;
  // 登りながら更新
  while (k > 0) {
    k = (k - 1) / 2;
    dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
  }
}

// [a,b)の最小値を求める
// 後ろのほうの引数は、計算の簡単のための引数。
// kは節点の番号、l, rはその節点が[l, r)に対応づいていることを表す。
// したがって、外からはquery(a, b, 0, 0, nn)として呼ぶ。
int query(int a, int b, int k, int l, int r) {
  // [a, b)と[l, r)が交差しなければ、INT_MAX
  if (r <= a || b <= l)
    return INT_MAX;

  // [a, b)が[l, r)を完全に含んでいれば、この節点の値
  if (a <= l && r <= b)
    return dat[k];
  else {
    // そうでなければ、2つの子の最小値
    int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
    int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
    return min(vl, vr);
  }
}

int main() {
  int h, w;
  cin >> h >> w;
  init(w + 10);
  set<int> se;
  srep(i, 1, w + 1) {
    update(i, 0);
    se.insert(i);
  }
  int INF = 1001001001;
  rep(i, h) {
    int a, b;
    scanf("%d%d", &a, &b);

    auto ite = se.lower_bound(a);
    int mi = INF;
    while (ite != se.end()) {
      int x = *ite;
      if (x > b + 1)
        break;
      int tmp = query(x, x + 1, 0, 0, nn);
      tmp += b + 1 - x;
      mi = min(mi, tmp);
      update(x, INF);
      ite = se.erase(ite);
    }
    if (mi < INF) {
      update(b + 1, mi);
      if (b < w)
        se.insert(b + 1);
    }
    // cout << se.size() << endl;
    int ans = query(1, w + 1, 0, 0, nn);
    ans += i + 1;
    if (ans >= INF)
      ans = -1;
    printf("%d\\n", ans);
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rrep(i, n) for (int i = 1; i <= (n); ++i)
#define drep(i, n) for (int i = (n)-1; i >= 0; --i)
#define srep(i, s, t) for (int i = s; i < t; ++i)
using namespace std;
typedef pair<int, int> P;
typedef long long int ll;
#define dame                                                                   \\
  {                                                                            \\
    puts("-1");                                                                \\
    return 0;                                                                  \\
  }
#define yn                                                                     \\
  { puts("Yes"); }                                                             \\
  else {                                                                       \\
    puts("No");                                                                \\
  }

const int MAX_N = 1 << 20;

// セグメント木を持つグローバル配列
int nn, dat[2 * MAX_N - 1];

// 初期化
void init(int n_) {
  // n_が小さいときの変な挙動を防ぐ
  if (n_ < 10)
    n_ = 10;
  // 簡単のため要素数を2のべき乗に
  nn = 1;
  while (nn < n_)
    nn *= 2;

  // 全ての値をINT_MAXに
  for (int i = 0; i < 2 * nn - 1; i++)
    dat[i] = INT_MAX;
}

// k番目の値(0-indexed)をaに変更
void update(int k, int a) {
  // 葉の接点
  k += nn - 1;
  dat[k] = a;
  // 登りながら更新
  while (k > 0) {
    k = (k - 1) / 2;
    dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
  }
}

// [a,b)の最小値を求める
// 後ろのほうの引数は、計算の簡単のための引数。
// kは節点の番号、l, rはその節点が[l, r)に対応づいていることを表す。
// したがって、外からはquery(a, b, 0, 0, nn)として呼ぶ。
int query(int a, int b, int k, int l, int r) {
  // [a, b)と[l, r)が交差しなければ、INT_MAX
  if (r <= a || b <= l)
    return INT_MAX;

  // [a, b)が[l, r)を完全に含んでいれば、この節点の値
  if (a <= l && r <= b)
    return dat[k];
  else {
    // そうでなければ、2つの子の最小値
    int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
    int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
    return min(vl, vr);
  }
}

int main() {
  int h, w;
  cin >> h >> w;
  init(w + 10);
  set<int> se;
  srep(i, 1, w + 1) {
    update(i, 0);
    se.insert(i);
  }
  int INF = 1001001001;
  rep(i, h) {
    int a, b;
    scanf("%d%d", &a, &b);

    auto ite = lower_bound(se.begin(), se.end(), a);
    int mi = INF;
    while (ite != se.end()) {
      int x = *ite;
      if (x > b + 1)
        break;
      int tmp = query(x, x + 1, 0, 0, nn);
      tmp += b + 1 - x;
      mi = min(mi, tmp);
      update(x, INF);
      ite = se.erase(ite);
    }
    if (mi < INF) {
      update(b + 1, mi);
      if (b < w)
        se.insert(b + 1);
    }
    // cout << se.size() << endl;
    int ans = query(1, w + 1, 0, 0, nn);
    ans += i + 1;
    if (ans >= INF)
      ans = -1;
    printf("%d\\n", ans);
  }
  return 0;
}