work(V){
    选择一条垂直分割线,它将V分割为V1,V2;
    d=min(work(V1),work(V2));
    取出垂直分割线往两端延伸d的区域内的所有点;
    求出区域内最近距离d’;
    return min(d,d’);
}
#include<bits/stdc++.h>
using namespace std;
int n,m,fa[100005];
double k;
struct point{//记录每个守卫信息的结构体
    double x,y;int id;
}a[100005],b[100005];
struct edge{//记录每一对有关系守卫信息的结构体
    int x,y;double w;
}e[200005];
bool cmp1(edge x,edge y){return x.w<y.w;}
bool cmp2(point x,point y){return x.x<y.x;}
bool cmp3(point x,point y){return x.y<y.y;}
int find(int x){
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}//并查集的路径压缩找爸爸操作,没的说
double dis(point x,point y){
    return max(fabs(x.x-y.x),fabs(x.y-y.y));
}//求两个点之间的(切比雪夫)距离的函数
double work(int l,int r){
    if(l==r)return 1e18;
//分治边界:该区间左右边界重合,最近点对距离视为无穷大
    int mid=(l+r)>>1,i=l,j=mid+1,k=i;
    double midline=(a[mid].x+a[mid+1].x)/2;
//midline垂直分割线
    double now=min(work(l,mid),work(mid+1,r));
    double d=now;
//归并排序:按照y坐标排序
    while(i<=mid&&j<=r){
        if(cmp3(a[i],a[j]))b[k]=a[i],i++,k++;
        else b[k]=a[j],j++,k++;
    }
    if(i<=mid)while(i<=mid)b[k]=a[i],i++,k++;
    else while(j<=r)b[k]=a[j],j++,k++;
    for(int i=l;i<=r;i++)a[i]=b[i];
    int L=1,R=0;
    for(int i=l;i<=r;i++)
        if(fabs(a[i].x-midline)<=d){
            while(L<=R&&(a[i].y-b[L].y)>=d)
                L++;
            for(int j=L;j<=R;j++){
                int x=find(a[i].id);
                int y=find(b[j].id);
                if(x!=y)
                    now=min(now,dis(a[i],b[j]));
            }
            b[++R]=a[i];
        }
    return now;
}
bool check(int mid){
    for(int i=1;i<=n;i++)fa[i]=i;//并查集
//因为我们的w二分到了第mid对点所要求的,
//所以第1-mid对点都能被满足要求,和解成为朋友
    for(int i=1;i<=mid;i++){
        int x=find(e[i].x),y=find(e[i].y);
        if(x!=y)fa[y]=x;
    }
    sort(a+1,a+n+1,cmp2);
//按照点的横坐标位置从小到大排序
    return work(1,n)>k;
//函数work返回的是当前w下,最近的两个点间距
}
int main(){
    scanf("%d%d%lf",&n,&m,&k);
//n个点,m对点之间有无向边相连,点之间最小距离要求是k
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
        a[i].id=i;
    }//读入每个点的横纵坐标
    for(int i=1;i<=m;i++)
        scanf("%d%d%lf",&e[i].x,&e[i].y,&e[i].w);
//读入有边相连的一对点:编号x,y及边权w
    sort(e+1,e+m+1,cmp1);
//按照边权从小到大排序,方便二分
    int l=0,r=m,mid,ans;//注意l的初始值
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%.3lf\n",e[ans].w);
    return 0;
}
原文:https://www.cnblogs.com/PPXppx/p/10362626.html