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

// C++ code to find number of distinct numbers
// in a subarray
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAX = 6e5 + 5;

// structure to store queries
struct Query {
  ll l, r, idx;
};

// cmp function to sort queries according to r
bool cmp(Query x, Query y) { return x.r < y.r; }

// updating the bit array
void update(ll idx, ll val, ll bit[], ll n) {
  for (; idx <= n; idx += idx & -idx)
    bit[idx] += val;
}

// querying the bit array
ll query(ll idx, ll bit[], ll n) {
  ll sum = 0;
  for (; idx > 0; idx -= idx & -idx)
    sum += bit[idx];
  return sum;
}

void answeringQueries(ll arr[], ll n, Query queries[], ll q) {
  // initialising bit array
  ll bit[n + 1];
  memset(bit, 0, sizeof(bit));

  // holds the rightmost index of any number
  // as numbers of a[i] are less than or equal to 10^6
  ll last_visit[MAX];
  memset(last_visit, -1, sizeof(last_visit));

  // answer for each query
  ll ans[q + 1];
  ll query_counter = 0;
  for (ll i = 0; i < n; i++) {
    // If last visit is not -1 update -1 at the
    // idx equal to last_visit[arr[i]]
    if (last_visit[arr[i]] != -1)
      update(last_visit[arr[i]] + 1, -1, bit, n);

    // Setting last_visit[arr[i]] as i and updating
    // the bit array accordingly
    last_visit[arr[i]] = i;
    update(i + 1, 1, bit, n);

    // If i is equal to r of any query store answer
    // for that query in ans[]
    while (query_counter < q && queries[query_counter].r == i) {
      ans[queries[query_counter].idx] =
          query(queries[query_counter].r + 1, bit, n) -
          query(queries[query_counter].l, bit, n);
      query_counter++;
    }
  }

  // print answer for each query
  for (ll i = 0; i < q; i++)
    cout << ans[i] << endl;
}

// driver code
int main() {
  ll n, q;
  cin >> n >> q;
  ll a[n];
  for (ll i = 0; i < n; ++i)
    cin >> a[i];

  Query queries[q];
  for (ll i = 0; i < q; ++i) {
    ll x, y;
    cin >> x >> y;
    x--;
    y--;
    queries[i].l = x;
    queries[i].r = y;
    queries[i].idx = i;
  }
  sort(queries, queries + q, cmp);
  answeringQueries(a, n, queries, q);
  return 0;
}


Error: TLE

Fixed submission:

// C++ implementation to find
// count of distinct elements
// in a range L to R for Q queries

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

// Function to merge the right
// and the left tree
void merge(vector<int> tree[], int treeNode) {
  int len1 = tree[2 * treeNode].size();
  int len2 = tree[2 * treeNode + 1].size();
  int index1 = 0, index2 = 0;

  // Fill this array in such a
  // way such that values
  // remain sorted similar to mergesort
  while (index1 < len1 && index2 < len2) {

    // If the element on the left part
    // is greater than the right part
    if (tree[2 * treeNode][index1] > tree[2 * treeNode + 1][index2]) {

      tree[treeNode].push_back(tree[2 * treeNode + 1][index2]);
      index2++;
    } else {
      tree[treeNode].push_back(tree[2 * treeNode][index1]);
      index1++;
    }
  }

  // Insert the leftover elements
  // from the left part
  while (index1 < len1) {
    tree[treeNode].push_back(tree[2 * treeNode][index1]);
    index1++;
  }

  // Insert the leftover elements
  // from the right part
  while (index2 < len2) {
    tree[treeNode].push_back(tree[2 * treeNode + 1][index2]);
    index2++;
  }
  return;
}

// Recursive function to build
// segment tree by merging the
// sorted segments in sorted way
void build(vector<int> tree[], int *arr, int start, int end, int treeNode) {
  // Base case
  if (start == end) {
    tree[treeNode].push_back(arr[start]);
    return;
  }
  int mid = (start + end) / 2;

  // Building the left tree
  build(tree, arr, start, mid, 2 * treeNode);

  // Building the right tree
  build(tree, arr, mid + 1, end, 2 * treeNode + 1);

  // Merges the right tree
  // and left tree
  merge(tree, treeNode);
  return;
}

// Function similar to query() method
// as in segment tree
int query(vector<int> tree[], int treeNode, int start, int end, int left,
          int right) {

  // Current segment is out of the range
  if (start > right || end < left) {
    return 0;
  }
  // Current segment completely
  // lies inside the range
  if (start >= left && end <= right) {

    // as the elements are in sorted order
    // so number of elements greater than R
    // can be find using binary
    // search or upper_bound
    return tree[treeNode].end() -
           upper_bound(tree[treeNode].begin(), tree[treeNode].end(), right);
  }

  int mid = (start + end) / 2;

  // Query on the left tree
  int op1 = query(tree, 2 * treeNode, start, mid, left, right);
  // Query on the Right tree
  int op2 = query(tree, 2 * treeNode + 1, mid + 1, end, left, right);
  return op1 + op2;
}

// Driver Code
int main() {

  int n, q;
  cin >> n >> q;
  int arr[n];
  for (int i = 0; i < n; ++i)
    cin >> arr[i];
  int next_right[n];
  // Initialising the tree
  vector<int> tree[4 * n];

  unordered_map<int, int> ump;

  // Construction of next_right
  // array to store the
  // next index of occurence
  // of elements
  for (int i = n - 1; i >= 0; i--) {
    if (ump[arr[i]] == 0) {
      next_right[i] = n;
      ump[arr[i]] = i;
    } else {
      next_right[i] = ump[arr[i]];
      ump[arr[i]] = i;
    }
  }
  // building the mergesort tree
  // by using next_right array
  build(tree, next_right, 0, n - 1, 1);

  int ans;
  // Queries one based indexing
  // Time complexity of each
  // query is log(N)

  // first query
  for (int i = 0; i < q; ++i) {
    int left1, right1;
    cin >> left1 >> right1;
    left1--;
    right1--;
    ans = query(tree, 1, 0, n - 1, left1, right1);
    cout << ans << "\\n";
  }
}