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

#include <bits/stdc++.h>
using namespace std;
template <typename T> struct BIT {
  int n;            // 元の数列のサイズ
  vector<T> bit[2]; // データ収納用
  void init(int n_) {
    n = n_ + 1;
    for (int j = 0; j < 2; j++) {
      bit[j].assign(n, 0);
    }
  }
  void add_sub(int p, int i, T x) {
    for (int j = i; j < n; j += j & -j) {
      bit[p][j] += x;
    }
  }
  void add(int l, int r, T x) { //[l,r]に加算
    add_sub(0, l, -x * (l - 1));
    add_sub(0, r + 1, x * r);
    add_sub(1, l, x);
    add_sub(1, r + 1, -x);
  }
  T sum_sub(int p, int i) {
    T s(0);
    for (int j = i; j > 0; j -= j & -j) {
      s += bit[p][j];
    }
    return s;
  }
  T sum(int i, int j) { //[i,j]のΣを計算
    return sum_sub(0, j) + sum_sub(1, j) * j - sum_sub(0, i - 1) -
           sum_sub(1, i - 1) * (i - 1);
  }
};
int main() {
  int N, Q;
  scanf("%d", &N);
  scanf("%d", &Q);
  vector<int> C(N); // i番目の石の色
  for (int i = 0; i < N; i++) {
    scanf("%d", &C.at(i));
  }
  map<pair<int, int>, vector<int>> query;
  // 左端がl,右端がrの時の答えを求めるクエリは何番目のクエリか
  vector<vector<int>> left(N);
  // Q個のクエリで右端がiであるようなクエリの左端の値
  for (int i = 0; i < Q; i++) {
    int l, r;
    scanf("%d", &l);
    scanf("%d", &r);
    query[make_pair(l - 1, r - 1)].push_back(i);
    // 左端がl,右端がrであるクエリが何番目であるかを配列に持たせる
    //(同じ内容のクエリが複数あるかもしれないのでintではなくvectorで複数持てるようにする)
    left.at(r - 1).push_back(l - 1);
    // 右端がrであるようなクエリの左端の値を配列に持たせる
  }
  BIT<int> rock;     // Binary Indexed Tree(1-indexed)
  rock.init(N + 10); // BITの前処理
  vector<int> RP(N, -1);
  // i番目の色の右端はどこか,初期値-1は存在しないことを示す(左から順に更新)
  vector<int> answer(Q, 1);
  // i番目のクエリの答えを持つ
  for (int i = 0; i < N; i++) {
    int memo = RP.at(C.at(i) - 1);
    // i番目の石の色の右端の位置が更新する前どこだったか(あるいはまだ現れていないか)
    RP.at(C.at(i) - 1) = i;
    // i番目の石の色の右端の位置をiに更新
    if (memo == -1) {
      rock.add(i + 1, i + 1, 1);
      // 初登場なのでi番目に1を足すだけ
    } else {
      rock.add(memo + 1, memo + 1, -1);
      rock.add(i + 1, i + 1, 1);
      // 2回目以降の登場なのでi番目に1を足すとともに、旧右端の情報は-1して消しておく
    }
    for (int j = 0; j < (int)left.at(i).size(); j++) {
      // 右端がiであるクエリそれぞれについてクエリの答えを以下求める
      int L = left.at(i).at(j);
      // 各クエリの左端がL、右端がi
      for (int k = 0; k < (int)query[make_pair(L, i)].size(); k++) {
        int number = query[make_pair(L, i)].at(k);
        // 左端と右端の情報からそのクエリが何番目かをnumberで受け取る
        answer.at(number) = (int)rock.sum(L + 1, i + 1);
        // number番目のクエリの答えは[L+1,i+1]の間の1の個数
        // つまり[L+1,i+1]の区間の和と一致
      }
    }
  }
  for (int i = 0; i < Q; i++) {
    printf("%d\\n", answer.at(i));
  }
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
template <typename T> struct BIT {
  int n;            // 元の数列のサイズ
  vector<T> bit[2]; // データ収納用
  void init(int n_) {
    n = n_ + 1;
    for (int j = 0; j < 2; j++) {
      bit[j].assign(n, 0);
    }
  }
  void add_sub(int p, int i, T x) {
    for (int j = i; j < n; j += j & -j) {
      bit[p][j] += x;
    }
  }
  void add(int l, int r, T x) { //[l,r]に加算
    add_sub(0, l, -x * (l - 1));
    add_sub(0, r + 1, x * r);
    add_sub(1, l, x);
    add_sub(1, r + 1, -x);
  }
  T sum_sub(int p, int i) {
    T s(0);
    for (int j = i; j > 0; j -= j & -j) {
      s += bit[p][j];
    }
    return s;
  }
  T sum(int i, int j) { //[i,j]のΣを計算
    return sum_sub(0, j) + sum_sub(1, j) * j - sum_sub(0, i - 1) -
           sum_sub(1, i - 1) * (i - 1);
  }
};
int main() {
  int N, Q;
  cin >> N >> Q;
  vector<int> C(N); // i番目の石の色
  for (int i = 0; i < N; i++) {
    cin >> C.at(i);
  }
  map<pair<int, int>, vector<int>> query;
  // 左端がl,右端がrの時の答えを求めるクエリは何番目のクエリか
  vector<vector<int>> left(N);
  // Q個のクエリで右端がiであるようなクエリの左端の値
  for (int i = 0; i < Q; i++) {
    int l, r;
    cin >> l >> r;
    query[make_pair(l - 1, r - 1)].push_back(i);
    // 左端がl,右端がrであるクエリが何番目であるかを配列に持たせる
    //(同じ内容のクエリが複数あるかもしれないのでintではなくvectorで複数持てるようにする)
    left.at(r - 1).push_back(l - 1);
    // 右端がrであるようなクエリの左端の値を配列に持たせる
  }
  BIT<int> rock;     // Binary Indexed Tree(1-indexed)
  rock.init(N + 10); // BITの前処理
  vector<int> RP(N, -1);
  // i番目の色の右端はどこか,初期値-1は存在しないことを示す(左から順に更新)
  vector<int> answer(Q, 1);
  // i番目のクエリの答えを持つ
  for (int i = 0; i < N; i++) {
    int memo = RP.at(C.at(i) - 1);
    // i番目の石の色の右端の位置が更新する前どこだったか(あるいはまだ現れていないか)
    RP.at(C.at(i) - 1) = i;
    // i番目の石の色の右端の位置をiに更新
    if (memo == -1) {
      rock.add(i + 1, i + 1, 1);
      // 初登場なのでi番目に1を足すだけ
    } else {
      rock.add(memo + 1, memo + 1, -1);
      rock.add(i + 1, i + 1, 1);
      // 2回目以降の登場なのでi番目に1を足すとともに、旧右端の情報は-1して消しておく
    }
    for (int j = 0; j < (int)left.at(i).size(); j++) {
      // 右端がiであるクエリそれぞれについてクエリの答えを以下求める
      int L = left.at(i).at(j);
      // 各クエリの左端がL、右端がi
      for (int k = 0; k < (int)query[make_pair(L, i)].size(); k++) {
        int number = query[make_pair(L, i)].at(k);
        // 左端と右端の情報からそのクエリが何番目かをnumberで受け取る
        answer.at(number) = (int)rock.sum(L + 1, i + 1);
        // number番目のクエリの答えは[L+1,i+1]の間の1の個数
        // つまり[L+1,i+1]の区間の和と一致
      }
    }
  }
  for (int i = 0; i < Q; i++) {
    cout << answer.at(i) << endl;
  }
}