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

#include <bits/stdc++.h>
using namespace std;

// 1点更新,区間和
class SegmentTree {
public:
  SegmentTree(int64_t n, int64_t value) {
    n_ = (int64_t)pow(2, ceil(log2(n)));
    nodes_.resize(2 * n_ - 1, value);
  }

  void add(int64_t x, int64_t diff) {
    nodes_[x + n_ - 1] += diff;
    if (x + n_ - 1 == 0) {
      return;
    }
    for (int64_t i = (x + n_ - 2) / 2;; i = (i - 1) / 2) {
      nodes_[i] = nodes_[2 * i + 1] + nodes_[2 * i + 2];
      if (i == 0) {
        break;
      }
    }
  }

  int64_t getSum(int64_t a, int64_t b, int64_t k = 0, int64_t l = 0,
                 int64_t r = -1) {
    if (r < 0) {
      r = n_;
    }
    if (r <= a || b <= l) {
      return 0;
    }
    if (a <= l && r <= b) {
      return nodes_[k];
    }
    int64_t lv = getSum(a, b, 2 * k + 1, l, (l + r) / 2);
    int64_t rv = getSum(a, b, 2 * k + 2, (l + r) / 2, r);
    return lv + rv;
  }

private:
  // 2のべき乗
  int64_t n_;
  vector<int64_t> nodes_;
};

struct Query {
  int64_t l, r, index;
};

int main() {
  int64_t N, Q;
  cin >> N >> Q;
  vector<int64_t> c(N);
  for (int64_t &C : c) {
    cin >> C;
    C--;
  }

  vector<Query> queries(Q);
  for (int64_t i = 0; i < Q; i++) {
    cin >> queries[i].l >> queries[i].r;
    queries[i].l--;
    queries[i].index = i;
  }

  sort(queries.begin(), queries.end(),
       [](Query &lhs, Query &rhs) { return lhs.r < rhs.r; });

  vector<int64_t> ans(Q);

  int64_t r = 0;
  SegmentTree st(N, 0);
  vector<int64_t> pos(N, -1);

  for (Query &query : queries) {
    while (r < query.r) {
      // c[r]が加わる
      if (pos[c[r]] != -1) {
        // 2回目以降の出現の場合、以前の記録を消す
        st.add(pos[c[r]], -1);
      }

      // 今回のものを記録
      pos[c[r]] = r;
      st.add(r, 1);

      r++;
    }

    ans[query.index] = st.getSum(query.l, query.r);
  }

  for (int64_t a : ans) {
    cout << a << endl;
  }
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

int main() {
  int64_t N, Q;
  cin >> N >> Q;
  vector<int64_t> c(N);
  for (int64_t &C : c) {
    cin >> C;
    C--;
  }

  vector<int64_t> l(Q), r(Q);
  for (int64_t i = 0; i < Q; i++) {
    cin >> l[i] >> r[i];
    l[i]--;
    r[i]--;
  }

  vector<int64_t> color2pre(N, -1), index2pre(N);
  for (int64_t i = 0; i < N; i++) {
    index2pre[i] = color2pre[c[i]];
    color2pre[c[i]] = i;
  }

  struct Query {
    int64_t l, r, index;
    bool operator<(const Query &rhs) const { return l < rhs.l; }
  };

  vector<Query> queries(Q);
  for (int64_t i = 0; i < Q; i++) {
    queries[i].l = l[i];
    queries[i].r = r[i];
    queries[i].index = i;
  }

  // rで降順ソート
  sort(queries.begin(), queries.end(),
       [](Query &lhs, Query &rhs) { return lhs.r > rhs.r; });

  // iを各色先頭として迎え入れる位置を検索する
  //(1)lがpreより大きい
  //(2)lがi以下
  //(3)rがi以上
  // の3条件が満たされるクエリに足せば良い
  // rがi以上となることが保証されているset(lでソートされる)を準備する
  multiset<Query> st;

  vector<int64_t> ans(Q, 0);

  int64_t index = 0;
  for (int64_t i = N - 1; i >= 0; i--) {
    while (index < Q && queries[index].r >= i) {
      st.insert(queries[index++]);
    }

    int64_t pre = index2pre[i];
    Query dummy;
    dummy.l = pre;
    auto left = st.upper_bound(dummy);
    dummy.l = i;
    auto right = st.upper_bound(dummy);
    //[left, right)のクエリにc[i]が先頭として位置する

    for (auto itr = left; itr != right; itr++) {
      ans[itr->index]++;
    }
  }

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