Mo's Algorithm
O((n + q)·√n)Answers offline range queries by sorting them in block order and moving the [l, r] window one element at a time. Works whenever add(x) and remove(x) are cheap. This version counts distinct values per query; customize add/remove for other statistics.
// use it on
SPOJ: DQUERY ↗
Number of distinct values in each queried range, the textbook Mo's application (and what this template computes as written).
// the code
// offline range queries; example: distinct values in [l, r]
vector<int> mo(vector<int>& a, vector<array<int, 2>>& queries) {
int n = a.size(), q = queries.size();
int B = max(1, (int)(n / sqrt(q + 1.0)));
vector<int> order(q), ans(q);
iota(order.begin(), order.end(), 0);
sort(order.begin(), order.end(), [&](int i, int j) {
int bi = queries[i][0] / B, bj = queries[j][0] / B;
if (bi != bj) return bi < bj;
return (bi & 1) ? queries[i][1] > queries[j][1]
: queries[i][1] < queries[j][1];
});
vector<int> cnt(*max_element(a.begin(), a.end()) + 1, 0);
int cur = 0, l = 0, r = -1;
auto add = [&](int i) { if (cnt[a[i]]++ == 0) cur++; };
auto rem = [&](int i) { if (--cnt[a[i]] == 0) cur--; };
for (int qi : order) {
auto [ql, qr] = queries[qi];
while (l > ql) add(--l);
while (r < qr) add(++r);
while (l < ql) rem(l++);
while (r > qr) rem(r--);
ans[qi] = cur;
}
return ans;
}