template/coldwater/manhattan-st
最大生成树将 Manhattan 距离转为 Chebyshev 距离,然后加入 \(\mathcal{O}(4n)\) 条边。
最小生成树:
#include <bits/stdc++.h>
#define MAXN (100010)
#define lowbit(x) ((x) & (- (x)))
int n;
struct P{
int x, y, id;
bool operator < (const P &rhs) const {
return x != rhs.x ? x < rhs.x : y < rhs.y;
}
}p[MAXN];
struct MST{
int tot, fa[MAXN], a[MAXN], b[MAXN];
std::pair<int, int> bit[MAXN];
struct Edge{
int u, v, w;
bool operator < (const Edge &rhs) const {
return w < rhs.w;
}
}edge[MAXN << 2];
int getfather(int x){ return x == fa[x] ? x : (fa[x] = getfather(fa[x])); }
int dis(P a, P b){ return std::abs(a.x - b.x) + std::abs(a.y - b.y); }
void insert(int x, int val, int pos){
for(int i = x; i; i -= lowbit(i)){
if(val < bit[i].first){
bit[i] = {val, pos};
}
}
}
int query(int x, int lmt){
int ret1 = INT_MAX, ret2 = -1;
for(int i = x; i <= lmt; i += lowbit(i)){
if(ret1 > bit[i].first){
ret1 = bit[i].first;
ret2 = bit[i].second;
}
}
return ret2;
}
int solve(){
//init()
tot = 0;
//
for(int dir = 0; dir <= 3; ++ dir){
if(dir & 1){
for(int i = 1; i <= n; ++ i) std::swap(p[i].x, p[i].y);
}
else if(dir){
for(int i = 1; i <= n; ++ i) p[i].x = - p[i].x;
}
std::sort(p + 1, n + p + 1);
for(int i = 1; i <= n; ++ i) a[i] = b[i] = p[i].y - p[i].x;
std::sort(b + 1, n + b + 1);
int lmt = std::unique(b + 1, n + b + 1) - b - 1;
for(int i = 1; i <= lmt; ++ i) bit[i] = {INT_MAX, -1};
for(int i = n; i; -- i){
int pos = std::lower_bound(b + 1, lmt + b + 1, a[i]) - b;
int ans = query(pos, lmt);
if(ans != -1){
edge[++ tot].u = p[i].id;
edge[tot].v = p[ans].id;
edge[tot].w = dis(p[i], p[ans]);
}
insert(pos, p[i].x + p[i].y, i);
}
}
std::sort(edge + 1, tot + edge + 1);
for(int i = 1; i <= n; ++ i) fa[i] = i;
int cnt = 0, ret = 0;
for(int i = 1; i <= tot; ++ i){
int u = getfather(edge[i].u);
int v = getfather(edge[i].v);
if(u == v) continue;
fa[u] = v;
++ cnt; ret += edge[i].w;
if(cnt == n - 1) break;
}
return ret;
}
}mst;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d%d", &p[i].x, &p[i].y);
p[i].id = i;
}
printf("%d\n", mst.solve());
return 0;
}