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

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
using namespace std;

int q, lim;
// セグ木
int dat[1 << 20 + 2];
// リーフ(一番下の葉)の最小
int low = 1 << 19 + 1;
// dat配列はどこまで埋まっているか
int size;
// 固体番号
int rnum[500000];
// 固体番号を円環するときに利用
map<int, int> num;

void add(int x) {
  // 固体番号(円環)追加
  num[x] = size;
  // 要素数追加
  dat[size] = 0;
  // 固体番号追加
  rnum[size - low] = x;
  // 配列が1つ埋まった
  size++;
  // 管理できる個体数が1つ減った
  lim--;

  int pos = size - 1;
  // ルートノードまで登りながら, 各ノードをインクリメント
  while (0 < pos) {
    dat[pos]++;
    pos = (pos - 1) / 2;
  }
}

// 配列のx番目が, dat配列の何番目か求める
int find(int x) {
  int pos = 0;
  // 左にもぐるか, 右にもぐるか決めつつ, リーフまでもぐる
  while (pos < low) {
    int left = pos * 2 + 1;
    int right = pos * 2 + 2;
    if (x <= dat[left]) {
      pos = left;
    } else {
      x -= dat[left];
      pos = right;
    }
  }
  return pos;
}

// dat配列のpos番目を削除する処理
void erase(int pos) {
  lim++;
  while (0 < pos) {
    dat[pos]--;
    pos = (pos - 1) / 2;
  }
}

int main(void) {
  while (1) {
    scanf("%d%d", &q, &lim);
    if (q == 0 && lim == 0)
      break;
    memset(dat, 0, sizeof(dat));
    memset(rnum, 0, sizeof(rnum));
    num.clear();
    size = low;
    for (int i = 0; i < q; i++) {
      int query, x;
      scanf("%d%d", &query, &x);
      if (query == 0) {
        add(x);
        if (lim < 0) {
          int pos = find(0);
          erase(pos);
        }
      } else if (query == 1) {
        int pos = find(x);
        erase(pos);
      } else if (query == 2) {
        int pos = find(x);
        printf("%d\\n", rnum[pos - low]);
      } else if (query == 3) {
        int pos = num[x];
        erase(pos);
      }
    }
    printf("end\\n");
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
using namespace std;

int q, lim;
// セグ木
int dat[1 << 20 + 2];
// リーフ(一番下の葉)の最小
int low = 1 << 19 + 1;
// dat配列はどこまで埋まっているか
int size;
// 固体番号
int rnum[500000];
// 固体番号を円環するときに利用
map<int, int> num;

void add(int x) {
  // 固体番号(円環)追加
  num[x] = size;
  // 要素数追加
  dat[size] = 0;
  // 固体番号追加
  rnum[size - low] = x;
  // 配列が1つ埋まった
  size++;
  // 管理できる個体数が1つ減った
  lim--;

  int pos = size - 1;
  // ルートノードまで登りながら, 各ノードをインクリメント
  while (0 < pos) {
    dat[pos]++;
    pos = (pos - 1) / 2;
  }
}

// 配列のx番目が, dat配列の何番目か求める
int find(int x) {
  int pos = 0;
  // 左にもぐるか, 右にもぐるか決めつつ, リーフまでもぐる
  while (pos < low) {
    int left = pos * 2 + 1;
    int right = pos * 2 + 2;
    if (x <= dat[left]) {
      pos = left;
    } else {
      x -= dat[left];
      pos = right;
    }
  }
  return pos;
}

// dat配列のpos番目を削除する処理
void erase(int pos) {
  lim++;
  while (0 < pos) {
    dat[pos]--;
    pos = (pos - 1) / 2;
  }
}

int main(void) {
  while (1) {
    scanf("%d%d", &q, &lim);
    memset(dat, 0, sizeof(0));
    memset(rnum, 0, sizeof(rnum));
    num.clear();
    size = low;
    for (int i = 0; i < q; i++) {
      int query, x;
      scanf("%d%d", &query, &x);
      if (query == 0) {
        add(x);
        if (lim < 0) {
          int pos = find(0);
          erase(pos);
        }
      } else if (query == 1) {
        int pos = find(x);
        erase(pos);
      } else if (query == 2) {
        int pos = find(x);
        printf("%d\\n", rnum[pos - low]);
      } else if (query == 3) {
        int pos = num[x];
        erase(pos);
      }
    }
    printf("end\\n");
  }

  return 0;
}