templates/mos-algorithm.cpp
compilable
$cat templates/mos-algorithm
Mo's Algorithm
Offline range query processing with Hilbert curve ordering for optimal cache performance.
#mo-algorithm#offline#range-query#hilbert-curve#two-pointers
Log in to track progress, save custom versions, and organize into collections.Log In
$cat source_code/
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 2e5 + 5;
int a[MAXN], n, q;
ll ans;
ll answers[MAXN];
int64_t hilbert(int x, int y, int pw, int rot) {
if (pw == 0) return 0;
int hp = 1 << (pw - 1);
int seg = (x < hp) ? ((y < hp) ? 0 : 3) : ((y < hp) ? 1 : 2);
seg = (seg + rot) & 3;
const int dr[] = {3, 0, 0, 1};
int nx = x & (x ^ hp), ny = y & (y ^ hp);
int64_t sub = int64_t(1) << (2 * pw - 2);
int64_t add = hilbert(nx, ny, pw - 1, (rot + dr[seg]) & 3);
return seg * sub + ((seg == 1 || seg == 2) ? add : sub - add - 1);
}
struct Query {
int l, r, idx;
int64_t ord;
bool operator<(const Query &o) const { return ord < o.ord; }
};
void add(int idx) {
// update ans when a[idx] enters range
}
void remove(int idx) {
// update ans when a[idx] leaves range
}
void solve() {
int pw = 1;
while ((1 << pw) < n) pw++;
vector<Query> queries(q);
for (int i = 0; i < q; i++) {
int l, r; cin >> l >> r; l--;
queries[i] = {l, r - 1, i, hilbert(l, r - 1, pw, 0)};
}
sort(queries.begin(), queries.end());
int cl = 0, cr = -1;
for (auto &[l, r, qi, _] : queries) {
while (cl > l) add(--cl);
while (cr < r) add(++cr);
while (cl < l) remove(cl++);
while (cr > r) remove(cr--);
answers[qi] = ans;
}
for (int i = 0; i < q; i++)
cout << answers[i] << '\n';
}58 linesutf-8
$cat explanation_notes.md
notes_viewer --renderedmarkdown (math enabled)
Mo's Algorithm
Process offline range queries on an array of size by reordering queries to minimize pointer movement.
How It Works
add() / remove() to move pointers to the target Hilbert Curve Ordering
Traditional Mo's sorts by . Hilbert curve ordering maps 2D coordinates to a 1D curve that preserves locality better, reducing total pointer movement by a constant factor.
When to Use
add and remove are or Implementation
add(idx) and remove(idx) with problem-specific logicadd should update the answer when element at idx enters the rangeremove should update the answer when element at idx leaves the rangeComplexity
add/remove