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

// g++ -std=c++14 test.cpp -o test.out

// BIT
// できること：累積和を動的に更新しながら区間和をO(logN)で取れる
// 区間ではなく一個の値ずつにしか加算できない
// セグ木より定数倍高速だが機能に制限あり

#include <algorithm>
#include <bitset>
#include <cassert>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdlib.h>
#include <string.h>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;

#define LL long long int
const LL INF = (1LL << 60);
const int INF_INT = 2147483647 - 1e6 - 1;
const LL mod = 1000000007ll;
const int mod_int = 1000000007;

// BIT
// できること：累積和を動的に更新しながら区間和をO(logN)で取れる
// 区間ではなく一個の値ずつにしか加算できない
// セグ木より定数倍高速だが機能に制限あり
// BITの配列は必ず1-indexedなことに注意
// このライブラリは外からは0-indexedとみなして処理できるよう改造済み

// Binary Indexed Tree (Fenwick Tree)
// https://youtu.be/lyHk98daDJo?t=7960
template <typename T> struct BIT {
  int n;
  vector<T> d;
  BIT(int n = 0) : n(n), d(n + 1) {}
  // 要素iにxを足す
  void add(int i, T x) {
    i++;
    for (i++; i <= n; i += i & -i) {
      d[i] += x;
    }
  }
  T sum(int i) {
    i++;
    T x = 0;
    for (i++; i; i -= i & -i) {
      x += d[i];
    }
    return x;
  }
  //[l,r)の和をとる
  T sum(int l, int r) { return sum(r - 1) - sum(l - 1); }
  // 格納されている数を表示　デバッグ用
  void debug() {
    cout << "bit:" << endl;
    for (int i = 0; i < n; i++) {
      cout << sum(i, i + 1) << " ";
    }
    cout << endl;
  }
};

LL N, Q;
vector<LL> C;
// r,l,index
vector<tuple<LL, LL, LL>> RLI;

vector<LL> ans;

void solve() {
  sort(RLI.begin(), RLI.end());
  // 色iが最後に出てきたインデックスをnum[i]とおく
  //-1ならまだ未登場
  vector<LL> num(N + 1, -1);

  BIT<LL> bit(N + 1);
  // 今見ている領域の右端
  int now_right = 0;
  for (int i = 0; i < Q; i++) {
    LL left = get<1>(RLI[i]);
    LL right = get<0>(RLI[i]);
    while (now_right <= right) {
      bit.add(now_right, 1);
      if (num[C[now_right]] != -1) {
        bit.add(num[C[now_right]], -1);
      }
      num[C[now_right]] = now_right;
      now_right++;
    }
    int index = get<2>(RLI[i]);
    ans[index] = bit.sum(left, right + 1);
  }
}

int main() {
  cin >> N >> Q;
  C = vector<LL>(N);
  RLI = vector<tuple<LL, LL, LL>>(Q);
  ans = vector<LL>(Q);
  for (int i = 0; i < N; i++)
    cin >> C[i];
  for (int i = 0; i < Q; i++) {
    LL l, r;
    cin >> l >> r;
    l--;
    r--;
    RLI[i] = tuple<LL, LL, LL>(r, l, i);
  }

  solve();

  for (int i = 0; i < Q; i++)
    cout << ans[i] << endl;
  return 0;
}

Error: TLE

Fixed submission:

// g++ -std=c++14 test.cpp -o test.out

// BIT
// できること：累積和を動的に更新しながら区間和をO(logN)で取れる
// 区間ではなく一個の値ずつにしか加算できない
// セグ木より定数倍高速だが機能に制限あり

#include <algorithm>
#include <bitset>
#include <cassert>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits.h>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdlib.h>
#include <string.h>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;

#define LL long long int
const LL INF = (1LL << 60);
const int INF_INT = 2147483647 - 1e6 - 1;
const LL mod = 1000000007ll;
const int mod_int = 1000000007;

// BIT
// できること：累積和を動的に更新しながら区間和をO(logN)で取れる
// 区間ではなく一個の値ずつにしか加算できない
// セグ木より定数倍高速だが機能に制限あり
// BITの配列は必ず1-indexedなことに注意
// このライブラリは外からは0-indexedとみなして処理できるよう改造済み

// Binary Indexed Tree (Fenwick Tree)
// https://youtu.be/lyHk98daDJo?t=7960
template <typename T> struct BIT {
  int n;
  vector<T> d;
  BIT(int n = 0) : n(n), d(n + 1) {}
  // 要素iにxを足す
  void add(int i, T x) {
    i++;
    for (i++; i <= n; i += i & -i) {
      d[i] += x;
    }
  }
  T sum(int i) {
    i++;
    T x = 0;
    for (i++; i; i -= i & -i) {
      x += d[i];
    }
    return x;
  }
  //[l,r)の和をとる
  T sum(int l, int r) { return sum(r - 1) - sum(l - 1); }
  // 格納されている数を表示　デバッグ用
  void debug() {
    cout << "bit:" << endl;
    for (int i = 0; i < n; i++) {
      cout << sum(i, i + 1) << " ";
    }
    cout << endl;
  }
};

LL N, Q;
vector<LL> C;
vector<pair<LL, LL>> RL;
map<pair<LL, LL>, queue<LL>> RL_to_ans_index;

vector<LL> ans;

void solve() {
  sort(RL.begin(), RL.end());
  // 色iが最後に出てきたインデックスをnum[i]とおく
  //-1ならまだ未登場
  vector<LL> num(N + 1, -1);

  BIT<LL> bit(N + 1);
  // 今見ている領域の右端
  int now_right = 0;
  for (int i = 0; i < Q; i++) {
    LL left = RL[i].second;
    LL right = RL[i].first;
    while (now_right <= right) {
      bit.add(now_right, 1);
      if (num[C[now_right]] != -1) {
        bit.add(num[C[now_right]], -1);
      }
      num[C[now_right]] = now_right;
      now_right++;
    }
    int index = RL_to_ans_index[RL[i]].front();
    RL_to_ans_index[RL[i]].pop();
    ans[index] = bit.sum(left, right + 1);
  }
}

int main() {
  cin >> N >> Q;
  C = vector<LL>(N);
  RL = vector<pair<LL, LL>>(Q);
  ans = vector<LL>(Q);
  for (int i = 0; i < N; i++)
    cin >> C[i];
  for (int i = 0; i < Q; i++) {
    LL l, r;
    cin >> l >> r;
    l--;
    r--;
    RL[i] = pair<LL, LL>(r, l);
    RL_to_ans_index[RL[i]].push(i);
  }

  solve();

  for (int i = 0; i < Q; i++)
    cout << ans[i] << endl;
  return 0;
}