- 性质:每个点向坐标系八个方向最近的点连边
- 实现:如y轴右偏45°区域,满足\(x_0<=x_1,y_0<=y_1\) 且 \(y_1-x_1>=y_0-x_0\)
因此\(x_1-x_0+y_1-y_0=(x_1+y_1)-(x_0+y_0)\),用线段树维护下标为\(y_1-x_1\),值\(x_1+y_1\)
每次修改前,查询下标大于\(y_0-x_0\),值尽量小
最后跑kruskar即可
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n,c[N],p[N],ad=2e5,ecnt,inf=0x3f3f3f3f,fa[N];
int g_fa(int u) {
if(fa[u]==u) return u;
return fa[u]=g_fa(fa[u]);
}
struct edge {
int x,y; ll z;
}E[N];
struct node {
int x,y,id;
}a[N];
bool cmp(node u,node v) {
if(u.x==v.x) return u.y<v.y;
return u.x<v.x;
}
bool cmp2(edge u,edge v) {return u.z<v.z;}
int lowbit(int i) {return i&(-i);}
void Update(int del,int sum,int s) {
del+=ad;
for(int i=del;i;i-=lowbit(i)) {
if(c[i]>sum) {
c[i]=sum,p[i]=s;
}
}
}
void query(int del,int sum,int s) {
del+=ad;
int pp,minn=inf;
for(int i=del;i<=ad*2;i+=lowbit(i)) {
if(c[i]<minn) {
minn=c[i];
pp=p[i];
}
}
if(minn!=inf) E[++ecnt]=(edge){s,pp,minn-sum};
}
void Build() {
memset(c,0x3f,sizeof(c));
sort(a+1,a+1+n,cmp);
for(int i=n;i>=1;i--) {
int u=a[i].y-a[i].x,v=a[i].y+a[i].x;
query(u,v,a[i].id);
Update(u,v,a[i].id);
}
}
void init() {
Build();
for(int i=1;i<=n;i++) swap(a[i].x,a[i].y);
Build();
for(int i=1;i<=n;i++) a[i].x*=-1;
Build();
for(int i=1;i<=n;i++) swap(a[i].x,a[i].y);
Build();
for(int i=1;i<=n;i++) fa[i]=i;
}
ll solve() {
sort(E+1,E+1+ecnt,cmp2);
ll ans=0;
for(int i=1,j=1;i<=ecnt&&j<n;i++) {
int u=g_fa(E[i].x),v=g_fa(E[i].y);
if(u!=v) {
fa[u]=v;
ans+=E[i].z;
j++;
}
}
return ans;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d%d",&a[i].x,&a[i].y); a[i].id=i;
}
init();
ll ans=solve();
printf("%lld\n",ans);
return 0;
}
曼哈顿最小生成树