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

#include <bits/stdc++.h>
#define ll long long
#define endl '\\n'
using namespace std;

struct query {
  ll left;
  ll right;
  ll index;
};

ll arr[500001];
query Q[500001];

ll blk = 1000; // Block-size=sqrt(n)=sqrt(30000).we precompute it so to prevent
               // runtime error.
ll frequency[500001]; // array to keep the frquency of the elements.
ll answer[500001];    // array to store the answers for all the given queries.
ll cnt = 0;           // tells the distinct-elements for each query.

// we compare according to the left-range of the query.(in ascending order)
bool compare(query a, query b) {
  if (a.left / blk != b.left / blk)
    return (a.left / blk < b.left / blk);
  else
    return (a.right < b.right);
}

void add(ll pos) {
  frequency[arr[pos]]++;
  if (frequency[arr[pos]] == 1)
    cnt++;
}

void remove(ll pos) {
  frequency[arr[pos]]--;
  if (frequency[arr[pos]] == 0)
    cnt--;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  ll n{0};
  ll q{0};
  cin >> n >> q;
  for (ll i = 0; i < n; i++)
    cin >> arr[i];

  for (ll i = 0; i < q; i++) {
    cin >> Q[i].left >> Q[i].right;
    Q[i].index = i;
    Q[i].left--;
    Q[i].right--;
  }

  sort(Q, Q + q, compare); // sorting the queries so we can reduce the movement
                           // of the global-left and global-right pointers.

  ll glo_left =
      0; // global-left pointer which point where the previous query started
  ll glo_right =
      -1; // global-right pointer which point where the previous query ended
  for (ll i = 0; i < q; i++) {
    ll cur_left = Q[i].left;   // current query left
    ll cur_right = Q[i].right; // current query right

    // to expand the previous range for the current range
    while (glo_left > cur_left) {
      glo_left--;
      add(glo_left);
    }

    while (glo_right < cur_right) {
      glo_right++;
      add(glo_right);
    }

    // to compress the previous range for the current range
    while (glo_left < cur_left) {
      remove(glo_left);
      glo_left++;
    }

    while (glo_right > cur_right) {
      remove(glo_right);
      glo_right--;
    }

    answer[Q[i].index] = cnt;
  }

  for (ll i = 0; i < q; i++)
    cout << answer[i] << endl;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define ll long long
#define endl '\\n'
using namespace std;

struct query {
  ll left;
  ll right;
  ll index;
};

ll arr[500001];
query Q[500001];

ll blk = 777; // Block-size=sqrt(n)=sqrt(30000).we precompute it so to prevent
              // runtime error.
ll frequency[500001]; // array to keep the frquency of the elements.
ll answer[500001];    // array to store the answers for all the given queries.
ll cnt = 0;           // tells the distinct-elements for each query.

// we compare according to the left-range of the query.(in ascending order)
bool compare(query a, query b) {
  if (a.left / blk != b.left / blk)
    return (a.left / blk < b.left / blk);
  else
    return (a.right < b.right);
}

void add(ll pos) {
  frequency[arr[pos]]++;
  if (frequency[arr[pos]] == 1)
    cnt++;
}

void remove(ll pos) {
  frequency[arr[pos]]--;
  if (frequency[arr[pos]] == 0)
    cnt--;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  ll n{0};
  ll q{0};
  cin >> n >> q;
  for (ll i = 0; i < n; i++)
    cin >> arr[i];

  for (ll i = 0; i < q; i++) {
    cin >> Q[i].left >> Q[i].right;
    Q[i].index = i;
    Q[i].left--;
    Q[i].right--;
  }

  sort(Q, Q + q, compare); // sorting the queries so we can reduce the movement
                           // of the global-left and global-right pointers.

  ll glo_left =
      0; // global-left pointer which point where the previous query started
  ll glo_right =
      -1; // global-right pointer which point where the previous query ended
  for (ll i = 0; i < q; i++) {
    ll cur_left = Q[i].left;   // current query left
    ll cur_right = Q[i].right; // current query right

    // to expand the previous range for the current range
    while (glo_left > cur_left) {
      glo_left--;
      add(glo_left);
    }

    while (glo_right < cur_right) {
      glo_right++;
      add(glo_right);
    }

    // to compress the previous range for the current range
    while (glo_left < cur_left) {
      remove(glo_left);
      glo_left++;
    }

    while (glo_right > cur_right) {
      remove(glo_right);
      glo_right--;
    }

    answer[Q[i].index] = cnt;
  }

  for (ll i = 0; i < q; i++)
    cout << answer[i] << endl;
}