暴力的做法应该是这样的,维护大小为k的堆,每次插入两点间距离并弹出堆顶。
然后这个做法显然是可以KD-Tree优化的,建立KD-Tree,然后如果该平面内最远点小于堆顶,则直接退出。就当做是复习很久没做的KD-Tree了。
不过有一个细节要注意,求最远点对,(1,2)->(2,1)算一对,所以堆的大小应该是2*k
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+7; struct point{ll d[2];}a[N]; struct node{int mn[2],mx[2],lc,rc;point a;}t[N]; priority_queue<ll,vector<ll>,greater<ll> >q; int n,m,rt,D; bool operator<(point a,point b){return a.d[D]<b.d[D];} void pushup(int x,int y) { t[x].mn[0]=min(t[x].mn[0],t[y].mn[0]); t[x].mn[1]=min(t[x].mn[1],t[y].mn[1]); t[x].mx[0]=max(t[x].mx[0],t[y].mx[0]); t[x].mx[1]=max(t[x].mx[1],t[y].mx[1]); } void build(int&k,int l,int r,int d) { k=0; if(l>r)return; D=d; int mid=l+r>>1; nth_element(a+l,a+mid,a+r+1); k=mid; t[k].mn[0]=t[k].mx[0]=t[k].a.d[0]=a[k].d[0]; t[k].mn[1]=t[k].mx[1]=t[k].a.d[1]=a[k].d[1]; build(t[k].lc,l,mid-1,d^1); if(t[k].lc)pushup(k,t[k].lc); build(t[k].rc,mid+1,r,d^1); if(t[k].rc)pushup(k,t[k].rc); } ll getdis(point a,point b) {return(a.d[0]-b.d[0])*(a.d[0]-b.d[0])+(a.d[1]-b.d[1])*(a.d[1]-b.d[1]);} ll getdis2(point a,node b) { ll ret=0; ret=max(ret,getdis(a,(point){b.mn[0],b.mn[1]})); ret=max(ret,getdis(a,(point){b.mn[0],b.mx[1]})); ret=max(ret,getdis(a,(point){b.mx[0],b.mn[1]})); ret=max(ret,getdis(a,(point){b.mx[0],b.mx[1]})); return ret; } void query(int k,point a) { ll dis=getdis(a,t[k].a); if(dis>q.top())q.pop(),q.push(dis); if(t[k].lc) { dis=getdis2(a,t[t[k].lc]); if(dis>q.top())query(t[k].lc,a); } if(t[k].rc) { dis=getdis2(a,t[t[k].rc]); if(dis>q.top())query(t[k].rc,a); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].d[0],&a[i].d[1]); build(rt,1,n,0); for(int i=1;i<=m*2;i++)q.push(0); for(int i=1;i<=n;i++)query(rt,a[i]); printf("%lld",q.top()); }