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

#include <algorithm>
#include <bitset>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

// range sum query using fenwick tree
// note index starts at 1

class fenwick_tree {
  vector<long> t;
  long size;

public:
  fenwick_tree(long n) {
    t.assign(n + 1, 0);
    size = n + 1;
  }

  long LSOne(long k) { // least significant 1-bit
    return k & (-k);
  }

  void update(long index, long val) { // can go up or go down
    for (; index < size; index += LSOne(index))
      t[index] += val;
  }

  long query_full(long a, long b) { // range query
    return query(b) - ((a <= 1) ? 0 : query(a - 1));
  }

  long query(long b) { // range query 1..b
    if (b < 1)
      return 0;

    long sum = 0;
    for (; b; b -= LSOne(b))
      sum += t[b];
    return sum;
  }
};

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

  int n, q, i, j, k, l, r, x, y, z, id;
  cin >> n >> q;
  vector<int> c(n + 1), v(n + 3, 0), last(n + 1, 0), rootid(n + 1, 0), ans(q);
  fenwick_tree ft(n + 1);
  vector<tuple<int, int, int>> query(q);

  for (i = 1; i <= n; i++)
    cin >> c[i];

  r = 0;
  for (i = n; i >= 1; i--) {
    v[i] = last[c[i]];
    last[c[i]] = i;
    rootid[i] = ++r;
  }

  for (i = 0; i < q; i++) {
    cin >> l >> r;
    query[i] = {l, r, i};
  }
  sort(query.rbegin(), query.rend());

  z = n + 1;
  for (auto p : query) {
    tie(l, r, id) = p;
    while (z > l) {
      z--;
      if (v[z] != 0)
        ft.update(v[z], 1);
    }

    x = ft.query_full(l, r);
    ans[id] = r + 1 - l - x;
  }

  for (auto p : ans)
    cout << p << "\\n";

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

#define MAXNODES                                                               \\
  25000010 // # of total possible nodes = initial N + log N * Query number
#define MAXN 601005 // # of versions

struct pst_node {
  long long left, right; // pointer to sons
  long long val;         // sum for range sum query (or range min/max)
  long long offset;      // value added to this range
};

class persistent_segment_tree {
public:
  long long size, top, root_top;

  // long long root_list[MAXN];
  // pst_node node_list[MAXNODES];

  vector<long long> root_list;
  vector<pst_node> node_list;

  persistent_segment_tree() {
    root_list.resize(MAXN);
    node_list.resize(MAXNODES);
  }

  long long build_tree(long long l, long long r,
                       vector<int> &a) { // returns node list
    if (l == r) {
      long long p = top++;

      node_list[p].left = -1;
      node_list[p].right = -1;
      node_list[p].val = a[l];
      node_list[p].offset = 0;

      return p; // return node #
    } else {
      long long p = top++;
      long long m = (l + r) >> 1;

      node_list[p].left = build_tree(l, m, a);
      node_list[p].right = build_tree(m + 1, r, a);
      node_list[p].val = 0;
      node_list[p].offset = 0;

      // range sum
      node_list[p].val = node_list[node_list[p].left].val + node_list[p].val +
                         node_list[node_list[p].right].val;

      return p;
    }
  }

  void initialize(vector<int> &a) { // initialize with a vector
    size = a.size();

    top = 0;
    build_tree(0, size - 1, a);

    root_list[0] = 0; // root #0
    root_top = 1;
  }

  long long
  update(long long root_id, long long pos,
         long long key) { // create a new tree by cloning with #root_id and
                          // updating position p with new value key
    long long ans = update_full(root_list[root_id], 0, size - 1, pos, key);
    root_list[root_top++] = ans;
    return ans;
  }

  long long update_full(long long pid, long long left, long long right,
                        long long pos,
                        long long key) { // pid = original tree node id
    if (left == right) {
      node_list[top].left = -1;
      node_list[top].right = -1;
      // node_list[top].val = key;
      node_list[top].val =
          node_list[pid].val + key; // use this for incremental value
      return top++;                 // return node #
    } else {
      long long p = top++;

      long long m = (left + right) >> 1;
      long long a, b;
      if (pos <= m) {
        a = update_full(node_list[pid].left, left, m, pos, key);
        b = node_list[pid].right;
      } else {
        a = node_list[pid].left;
        b = update_full(node_list[pid].right, m + 1, right, pos, key);
      }

      node_list[p].left = a;
      node_list[p].right = b;
      node_list[p].offset = 0;

      // range sum
      node_list[p].val = node_list[a].val + node_list[b].val;
      return p;
    }
  }

  long long update_range(long long root_id, long long l, long long r,
                         long long off) {
    long long ans =
        update_range_full(root_list[root_id], 0, size - 1, l, r, off);
    root_list[root_top++] = ans;
    return ans;
  }

  long long update_range_full(long long pid, long long left, long long right,
                              long long l, long long r, long long off) {
    if ((left >= l) && (right <= r)) {
      // fully included in this range. set offset instead of change individual
      // nodes
      node_list[top].left = node_list[pid].left;
      node_list[top].right = node_list[pid].right;

      if (node_list[top].left == -1) {
        // leave node
        node_list[top].val = node_list[pid].val + off;
        // node_list[top].offset = node_list[pid].offset + off;	// not relevant
      } else {
        node_list[top].offset = node_list[pid].offset + off;
        node_list[top].val = node_list[node_list[pid].left].val +
                             node_list[node_list[pid].right].val +
                             (right + 1 - left) * node_list[top].offset;
      }
      return top++; // return node #
    } else {
      long long p = top++;

      long long m = (left + right) >> 1;
      long long a, b;

      if (m >= l)
        a = update_range_full(node_list[pid].left, left, m, l, r, off);
      else
        a = node_list[pid].left;

      if (m + 1 <= r)
        b = update_range_full(node_list[pid].right, m + 1, right, l, r, off);
      else
        b = node_list[pid].right;

      node_list[p].left = a;
      node_list[p].right = b;

      // range sum
      node_list[p].val = node_list[a].val + node_list[b].val +
                         node_list[pid].offset * (right + 1 - left);
      node_list[p].offset =
          node_list[pid].offset; // no need to change offset since the new off
                                 // doesn't apply to the full range
      return p;
    }
  }

  long long query(long long root_id, long long l,
                  long long r) { // get range sum between l and r starting from
                                 // the segment tree indicated by root_id
    if (l > r) {
      return 0;
    }
    return query_full(root_list[root_id], 0, size - 1, l, r, 0);
  }

  long long query_full(
      long long pid, long long left, long long right, long long l, long long r,
      long long off) { // left/right = current range, l/r = intended query
                       // range; off = carried (uncommitted) offset from parents
    if ((left >= l) && (right <= r))
      return node_list[pid].val + off * (right + 1 - left); // commit offset
    long long m = (left + right) >> 1, ans = 0;

    if (m >= l) {
      ans += query_full(node_list[pid].left, left, m, l, r,
                        off + node_list[pid].offset);
    }
    if (m + 1 <= r) {
      ans += query_full(node_list[pid].right, m + 1, right, l, r,
                        off + node_list[pid].offset);
    }
    return ans;
  }
};

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

  int n, q, i, j, k, ans, l, r, x, y;
  cin >> n >> q;
  vector<int> c(n + 1), v(n + 3, 0), last(n + 1, 0), rootid(n + 1, 0);
  persistent_segment_tree tr;
  tr.initialize(v);

  for (i = 1; i <= n; i++)
    cin >> c[i];

  r = 0;
  for (i = n; i >= 1; i--) {
    v[i] = last[c[i]];
    tr.update(r, v[i], 1);
    last[c[i]] = i;
    rootid[i] = ++r;
  }

  for (i = 1; i <= n; i++) {
  }

  while (q--) {
    cin >> l >> r;
    x = tr.query(rootid[l], l, r);
    // y = tr.query(r, 0, r);
    ans = r + 1 - l - x;
    cout << ans << "\\n";
  }

  return 0;
}