Topics
Coordinate compression is a technique used to reduce the range of values in a dataset while preserving the relative order of the elements. It’s particularly useful when you have a problem where the actual values don’t matter as much as their relative positions.
How it Works (with Frequency Arrays)
- Create a Sorted Set of Unique Values: Extract all unique values from your input data and store them in a sorted set (like
std::set
in C++). This automatically removes duplicates and sorts the values - Map Original Values to Compressed Coordinates: Create a mapping (e.g., using
std::map
or an array) from the original values to their compressed coordinates. The compressed coordinates will be in the range[0, number of unique values - 1]
- Build the Frequency Array: Now, instead of using the original values as indices in your frequency array, use the compressed coordinates
Example: Range Query Counter
You are given N
ranges [L₁, R₁], [L₂, R₂], ..., [Lₙ, Rₙ]
where 1 ≤ N ≤ 5000
and -10⁹ ≤ Lᵢ, Rᵢ ≤ 10⁹
. For each range [Lᵢ, Rᵢ]
, you need to count maximum number of ranges covering any point
Idea
Sure there are simple ways to solve the problem, but we will showcase how coordinate compression can be used in conjunction with frequency arrays. Observe that:
- The actual values of coordinates don’t matter, only their relative positions matter
- The range of possible coordinates (-10⁹ to 10⁹) is too large for a direct frequency array
Algorithm
- Use coordinate compression to map the original coordinates to a smaller range
- For each compressed range:
- Add 1 to all positions in the frequency array from L to R
- This indicates that all these positions L to R are coverd by a range
- Track running max:
ans = max(freq[pos], ans)
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> ranges(n);
set<int> coords; // Will store unique coordinates
// Read input and collect unique coordinates
for (int i = 0; i < n; i++) {
cin >> ranges[i].first >> ranges[i].second;
coords.insert(ranges[i].first);
coords.insert(ranges[i].second);
}
// Create mapping from original coordinates to compressed ones
map<int, int> coord_map;
int idx = 0;
for (int coord : coords) {
coord_map[coord] = idx++;
}
// Convert original ranges to compressed ranges
vector<pair<int, int>> compressed_ranges(n);
for (int i = 0; i < n; i++) {
compressed_ranges[i].first = coord_map[ranges[i].first];
compressed_ranges[i].second = coord_map[ranges[i].second];
}
// Create frequency array using compressed coordinates
vector<int> freq(coords.size(), 0);
// Mark range coverages
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = compressed_ranges[i].first; j <= compressed_ranges[i].second;
j++) {
freq[j]++;
res = max(res, freq[j]);
}
}
cout << res << "\n";
return 0;
}
Input:
5
1 4
2 3
3 6
5 7
-1000 1001
Output:
4
Time Complexity
- Coordinate compression: O(N log N) (since C++ sets and maps have log N insert)
- Processing ranges: O(N * K) where K is the number of unique coordinates
- Overall: O(N * K) where K ≤ 2N (since each range contributes at most 2 unique coordinates)
Space Complexity
- O(N) for storing ranges and frequency array