Pattern Reference
Coordinate Compression
"Map sparse coordinates to dense indices for segment trees, BIT, DP."
Loading...
Deep Dive Tutorial
Coordinate compression solves the "values are too large for array indexing" problem. If you need a Fenwick tree on values up to 10^9, you can't allocate 10^9 slots. Instead: collect all values that appear, sort them, and replace each value with its rank (1..n). The relative order is preserved — that's all you need for count-based queries.
The Technique
Coordinate compression template
// Given values that can be up to 10^9, compress to ranks 1..n
function compress(values) {
// Step 1: collect all unique values
const unique = [...new Set(values)].sort((a,b) => a-b);
// Step 2: build rank map
const rank = new Map(unique.map((v,i) => [v, i+1])); // 1-indexed
// Step 3: replace values with ranks
return { ranks: values.map(v => rank.get(v)), n: unique.length, rank, unique };
}
// Lower bound: rank of x = first rank with unique[rank-1] >= x
// Used for: "count elements less than x" = query(lowerBound(x) - 1)
// Example: values = [100, 50, 200, 50, 100]
// unique = [50, 100, 200] → ranks: [2, 1, 3, 1, 2]
// Fenwick tree of size 3 instead of 200!
// Combined with Fenwick tree for counting/inversions:
function countInversions(nums) {
const unique = [...new Set(nums)].sort((a,b)=>a-b);
const rank = new Map(unique.map((v,i)=>[v,i+1]));
const n = unique.length;
const bit = new Array(n+1).fill(0);
const update = i => { for(;i<=n;i+=i&(-i)) bit[i]++; };
const query = i => { let s=0; for(;i>0;i-=i&(-i)) s+=bit[i]; return s; };
let inversions = 0;
for(const x of nums) {
const r = rank.get(x);
inversions += query(n) - query(r); // count elements already inserted that are > x
update(r);
}
return inversions;
}Worked Problems
minimize-2
When to use coordinate compression:
- Values up to 10^9 but only n ≤ 10^5 distinct values appear
- Need a Fenwick/Segment tree indexed by VALUE (not position)
- Counting/querying by value range: how many elements ≤ x
Template: collect all values, sort, deduplicate, map each → rank. Then use ranks as array indices.
Offline vs online: Coordinate compression requires knowing all values upfront (offline). For online queries (values arrive one by one), use a balanced BST or dynamic segment tree instead.
- Values up to 10^9 but only n ≤ 10^5 distinct values appear
- Need a Fenwick/Segment tree indexed by VALUE (not position)
- Counting/querying by value range: how many elements ≤ x
Template: collect all values, sort, deduplicate, map each → rank. Then use ranks as array indices.
Offline vs online: Coordinate compression requires knowing all values upfront (offline). For online queries (values arrive one by one), use a balanced BST or dynamic segment tree instead.