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

// Mo's algorithm
// 例題：数列の区間内の要素の種類数を求める  ABC174 F

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

struct Mo {
  vector<int> left, right, index; // offline query
  int window;                     // bucket width
  int nl, nr, ptr;                // [nl,nr)

  vector<int> a;   // input
  vector<int> res; // output
  // add,delで書き換えていく
  vector<int> count;
  int sum;

  Mo(int n, vector<int> aa)
      : window((int)sqrt(n)), nl(0), nr(0), ptr(0), count(n, 0), sum(0) {
    a = aa;
  }

  /* query [l,r) 0-indexed */
  void push(int l, int r) { left.push_back(l), right.push_back(r); }

  /* query sort */
  void build() {
    index.resize(left.size());
    res.resize(left.size());
    iota(index.begin(), index.end(), 0);
    sort(index.begin(), index.end(), [&](int a, int b) {
      if (left[a] / window != left[b] / window)
        return left[a] < left[b];
      if ((left[a] / window) % 2)
        return right[a] > right[b];
      return right[a] < right[b];
    });
  }

  /* 問題ごとに書き換える */
  void add(int id) {
    if (count[a[id]]++ == 0)
      sum++;
    return;
  };
  void del(int id) {
    if (--count[a[id]] == 0)
      sum--;
    return;
  }

  /* 区間を次のquery用に伸縮させる */
  void next() {
    int i = index[ptr++];
    while (left[i] < nl)
      add(--nl);
    while (nr < right[i])
      add(nr++);
    while (nl < left[i])
      del(nl++);
    while (right[i] < nr)
      del(--nr);
    res[i] = sum;
  } // 返り値はquery-index
};

int n, q, l, r;

int main() {
  cin >> n >> q;
  vector<int> a(n);
  rep(i, n) {
    cin >> a[i];
    a[i]--;
  }
  Mo mo(n, a);
  rep(i, q) {
    cin >> l >> r;
    mo.push(--l, r);
  }

  mo.build();
  rep(i, q) mo.next();
  rep(i, q) cout << mo.res[i] << "\\n";
  return 0;
}

Error: TLE

Fixed submission:

// Mo's algorithm
// 例題：数列の区間内の要素の種類数を求める  ABC174 F

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

struct Mo {
  vector<int> left, right, index; // offline query
  int window;                     // bucket width
  int nl, nr, ptr;                // [nl,nr)

  vector<int> a;   // input
  vector<int> res; // output
  // add,delで書き換えていく
  vector<int> count;
  int sum;

  Mo(int n, vector<int> aa)
      : window((int)sqrt(n)), nl(0), nr(0), ptr(0), count(n, 0), sum(0) {
    a = aa;
  }

  /* query [l,r) 0-indexed */
  void push(int l, int r) { left.push_back(l), right.push_back(r); }

  /* query sort */
  void build() {
    index.resize(left.size());
    res.resize(left.size());
    iota(index.begin(), index.end(), 0);
    sort(index.begin(), index.end(), [&](int a, int b) {
      if (left[a] / window != left[b] / window)
        return left[a] < left[b];
      if ((left[a] / window) % 2)
        return right[a] > right[b];
      return right[a] < right[b];
    });
  }

  /* 問題ごとに書き換える */
  void add(int id) {
    if (count[a[id]]++ == 0)
      sum++;
    return;
  };
  void del(int id) {
    if (--count[a[id]] == 0)
      sum--;
    return;
  }

  /* 区間を次のquery用に伸縮させる */
  void next() {
    int i = index[ptr++];
    while (left[i] < nl)
      add(--nl);
    while (nr < right[i])
      add(nr++);
    while (nl < left[i])
      del(nl++);
    while (right[i] < nr)
      del(--nr);
    res[i] = sum;
  } // 返り値はquery-index
};

int n, q, l, r;

int main() {
  cin >> n >> q;
  vector<int> a(n);
  rep(i, n) {
    cin >> a[i];
    a[i]--;
  }
  Mo mo(n, a);
  rep(i, q) {
    cin >> l >> r;
    mo.push(--l, r);
  }

  mo.build();
  rep(i, q) mo.next();
  rep(i, q) cout << mo.res[i] << endl;
  return 0;
}