Manhattan Distance¶
Definition¶
For points
Defined this way, the distance corresponds to the so-called Manhattan (taxicab) geometry, in which the points are considered intersections in a well designed city, like Manhattan, where you can only move on the streets horizontally or vertically, as shown in the image below:

This images show some of the smallest paths from one black point to the other, all of them with length
There are some interesting tricks and algorithms that can be done with this distance, and we will show some of them here.
Farthest pair of points in Manhattan distance¶
Given
Let's think first in one dimension, so
So, for example, we can try to have
Notice that we can extend this idea further for 2 (or more!) dimensions. For
As we made
The code below generalizes this to
long long ans = 0;
for (int msk = 0; msk < (1 << d); msk++) {
long long mx = LLONG_MIN, mn = LLONG_MAX;
for (int i = 0; i < n; i++) {
long long cur = 0;
for (int j = 0; j < d; j++) {
if (msk & (1 << j)) cur += p[i][j];
else cur -= p[i][j];
}
mx = max(mx, cur);
mn = min(mn, cur);
}
ans = max(ans, mx - mn);
}
Rotating the points and Chebyshev distance¶
It's well known that, for all
To prove this, we just need to analyze the signs of
We may apply this equation to the Manhattan distance formula to find out that
The last expression in the previous equation is the Chebyshev distance of the points
the Manhattan distance between the points
Also, we may realize that
Here's an image to help visualizing the transformation:

Manhattan Minimum Spanning Tree¶
The Manhattan MST problem consists of, given some points in the plane, find the edges that connect all the points and have a minimum total sum of weights. The weight of an edge that connects two points is their Manhattan distance. For simplicity, we assume that all points have different locations.
Here we show a way of finding the MST in

The 8 octants relative to a point S
The algorithm shown here was first presented in a paper from H. Zhou, N. Shenoy, and W. Nichollos (2002). There is also another know algorithm that uses a Divide and conquer approach by J. Stolfi, which is also very interesting and only differ in the way they find the nearest neighbor in each octant. They both have the same complexity, but the one presented here is easier to implement and has a lower constant factor.
First, let's understand why it is enough to consider only the nearest neighbor in each octant. The idea is to show that for a point

Intuitively, the limitation of the octant makes it impossible that
Therefore, the main question is how to find the nearest neighbor in each octant for every single of the
Nearest Neighbor in each Octant in O(n log n)¶
For simplicity we focus on the NNE octant (
We will use a sweep-line approach. We process the points from south-west to north-east, that is, by non-decreasing

In black with an arrow you can see the direction of the line-sweep. All the points below this lines are in the active set, and the points above are still not processed. In green we see the points which are in the octant of the processed point. In red the points that are not in the searched octant.

In this image we see the active set after processing the point
When we add a new point point
The next question is how to efficiently find which points
Because no points in the active set are in the
You can try to visualize this on the images above by thinking of the ordering of
This means that if we keep the active set ordered by
In summary we:
- Sort the points by
- For every point, we iterate over the active set starting with the point with the largest
- We add the point
- Rotate the points and repeat until we iterate over all the octants.
- Apply Kruskal algorithm in the list of edges to get the MST.
Below you can find a implementation, based on the one from KACTL.
struct point {
long long x, y;
};
// Returns a list of edges in the format (weight, u, v).
// Passing this list to Kruskal algorithm will give the Manhattan MST.
vector<tuple<long long, int, int>> manhattan_mst_edges(vector<point> ps) {
vector<int> ids(ps.size());
iota(ids.begin(), ids.end(), 0);
vector<tuple<long long, int, int>> edges;
for (int rot = 0; rot < 4; rot++) { // for every rotation
sort(ids.begin(), ids.end(), [&](int i, int j){
return (ps[i].x + ps[i].y) < (ps[j].x + ps[j].y);
});
map<int, int, greater<int>> active; // (xs, id)
for (auto i : ids) {
for (auto it = active.lower_bound(ps[i].x); it != active.end();
active.erase(it++)) {
int j = it->second;
if (ps[i].x - ps[i].y > ps[j].x - ps[j].y) break;
assert(ps[i].x >= ps[j].x && ps[i].y >= ps[j].y);
edges.push_back({(ps[i].x - ps[j].x) + (ps[i].y - ps[j].y), i, j});
}
active[ps[i].x] = i;
}
for (auto &p : ps) { // rotate
if (rot & 1) p.x *= -1;
else swap(p.x, p.y);
}
}
return edges;
}
Problems¶
- AtCoder Beginner Contest 178E - Dist Max
- CodeForces 1093G - Multidimensional Queries
- CodeForces 944F - Game with Tokens
- AtCoder Code Festival 2017D - Four Coloring
- The 2023 ICPC Asia EC Regionals Online Contest (I) - J. Minimum Manhattan Distance
- Petrozavodsk Winter Training Camp 2016 Contest 4 - B. Airports