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

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC push_options
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx")
#pragma comment(linker, "/STACK:2000000000")

#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using ll = int64_t;
#define rep(i, j, n) for (int i = j; i < (int)n; ++i)

class Mo {
public:
  Mo(int n, int q) : bucket_size((int)sqrt(n)), query_idx(q), in(n) {
    for (int i = 0; i < q; ++i)
      query_idx[i] = i;
  }

  // [l, r)
  void push(int l, int r) {
    left.emplace_back(l);
    right.emplace_back(r);
  }

  void run() {
    std::sort(begin(query_idx), end(query_idx), [&](int i, int j) {
      if (left[i] / bucket_size != left[j] / bucket_size)
        return left[i] < left[j]; // 違うバケットにいたら
      else if (left[i] / bucket_size % 2 == 0)
        return right[i] < right[j]; // 同じバケットにいたら
      return right[i] > right[j];
    });
    int nl = 0, nr = 0;
    for (int idx : query_idx) {
      while (nl > left[idx])
        move(--nl);
      while (nr < right[idx])
        move(nr++);
      while (nl < left[idx])
        move(nl++);
      while (nr > right[idx])
        move(--nr);
      solve(idx);
    }
  }

private:
  int bucket_size;
  std::vector<int> left, right, query_idx;
  std::vector<bool> in;
  void move(int idx) {
    in[idx].flip();
    if (in[idx])
      insert(idx);
    else
      erase(idx);
  }

  // 問題ごとに変える
  void insert(int idx);
  void erase(int idx);
  void solve(int idx);
};

// ---- mo 用 ----
vector<int> cnt(500001), a, ans;
int num_kind = 0;

void Mo::insert(int idx) {
  if (cnt[a[idx]] == 0)
    ++num_kind;
  ++cnt[a[idx]];
}

void Mo::erase(int idx) {
  if (cnt[a[idx]] == 1)
    --num_kind;
  --cnt[a[idx]];
}

void Mo::solve(int idx) { ans[idx] = num_kind; }
// ----

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n, q, l, r;
  cin >> n >> q;
  a.resize(n);
  for (int i = 0; i < n; i++)
    cin >> a[i];
  Mo mo(n, q);
  for (int i = 0; i < q; i++) {
    cin >> l >> r;
    mo.push(l - 1, r);
  }
  ans.resize(q);

  mo.run();
  for (int i = 0; i < q; i++)
    cout << ans[i] << '\\n';
  return 0;
}


Error: TLE

Fixed submission:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC push_options
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx")

#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <queue>
#include <string>
#include <vector>
using namespace std;
using ll = int64_t;
#define rep(i, j, n) for (int i = j; i < (int)n; ++i)

class Mo {
public:
  Mo(int n, int q) : bucket_size((int)sqrt(n)), query_idx(q), in(n) {
    for (int i = 0; i < q; ++i)
      query_idx[i] = i;
  }

  // [l, r)
  void push(int l, int r) {
    left.emplace_back(l);
    right.emplace_back(r);
  }

  void run() {
    std::sort(begin(query_idx), end(query_idx), [&](int i, int j) {
      if (left[i] / bucket_size != left[j] / bucket_size)
        return left[i] < left[j]; // 違うバケットにいたら
      else if (left[i] / bucket_size % 2 == 0)
        return right[i] < right[j]; // 同じバケットにいたら
      return right[i] > right[j];
    });
    int nl = 0, nr = 0;
    for (int idx : query_idx) {
      while (nl > left[idx])
        move(--nl);
      while (nr < right[idx])
        move(nr++);
      while (nl < left[idx])
        move(nl++);
      while (nr > right[idx])
        move(--nr);
      solve(idx);
    }
  }

private:
  int bucket_size;
  std::vector<int> left, right, query_idx;
  std::vector<bool> in;
  void move(int idx) {
    in[idx].flip();
    if (in[idx])
      insert(idx);
    else
      erase(idx);
  }

  // 問題ごとに変える
  void insert(int idx);
  void erase(int idx);
  void solve(int idx);
};

// ---- mo 用 ----
vector<int> cnt(500001), a, ans;
int num_kind = 0;

void Mo::insert(int idx) {
  if (cnt[a[idx]] == 0)
    ++num_kind;
  ++cnt[a[idx]];
}

void Mo::erase(int idx) {
  if (cnt[a[idx]] == 1)
    --num_kind;
  --cnt[a[idx]];
}

void Mo::solve(int idx) { ans[idx] = num_kind; }
// ----

int main() {
  int n, q, l, r;
  cin >> n >> q;
  a.resize(n);
  for (int i = 0; i < n; i++)
    cin >> a[i];
  Mo mo(n, q);
  for (int i = 0; i < q; i++) {
    cin >> l >> r;
    mo.push(l - 1, r);
  }
  ans.resize(q);

  mo.run();
  for (int i = 0; i < q; i++)
    cout << ans[i] << '\\n';
  return 0;
}