题意:已知平面内 \(N\) 个点的坐标,求欧氏距离下的第 \(K\) 远点对。两个点 \(P(x_1,y_1)\) 和 \(Q(x_2,y_2)\) 的欧氏距离定义为 \(\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}\)。
分析:按照\(KD-Tree\)的方式对这n个点建树,建立一个小根堆,维护当前最远的k个点对距离,但是因为如果\(dis(i,j)\)在堆中,那么\(dis(j,i)\)也要在堆中,因此实际上堆的大小是\(2k\),最后的答案就是堆顶的值。建树之后,遍历每一个点(以下称为当前节点)去看能不能更新堆。对于每一棵子树,首先判断根节点与当前节点之间的距离能否更新堆,然后对于该子树的左右儿子节点,根据\(KD-Tree\)的性质,每一个节点维护了一个长方形的信息(一棵子树包含了若干个节点,这个长方形是最小的能够包括所有子树中节点的长方形,也就是建树时记录了每个子树中所有节点横坐标和纵坐标的最值),当前节点到这个长方形的最远距离一定是到四个顶点的距离之一,如果最远距离都不能更新堆顶,那就没必要递归这棵子树了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1e5+5;
const int M=2e4+5;
const int mod=1e9+7;
int n,k;
int l[N],r[N],d[N],u[N],ls[N],rs[N];
int divi[N];
priority_queue<ll,vector<ll>,greater<ll> >q;
struct node{
int x,y;
}a[N];
void update(int p){
l[p]=r[p]=a[p].x;d[p]=u[p]=a[p].y;
if(ls[p]){
l[p]=min(l[p],l[ls[p]]);r[p]=max(r[p],r[ls[p]]);
d[p]=min(d[p],d[ls[p]]);u[p]=max(u[p],u[ls[p]]);
}
if(rs[p]){
l[p]=min(l[p],l[rs[p]]);r[p]=max(r[p],r[rs[p]]);
d[p]=min(d[p],d[rs[p]]);u[p]=max(u[p],u[rs[p]]);
}
}
bool cmp1(node x,node y){
return x.x<y.x;
}
bool cmp2(node x,node y){
return x.y<y.y;
}
int build(int l,int r){
if(l>r)return 0;
int mid=(l+r)>>1;
double avx=0,avy=0,fcx=0,fcy=0;
for(int i=l;i<=r;++i){
avx+=a[i].x;avy+=a[i].y;
}
avx=avx*1.0/(r-l+1);avy=avy*1.0/(r-l+1);
for(int i=l;i<=r;++i){
fcx+=(avx-a[i].x)*(avx-a[i].x);
fcy+=(avy-a[i].y)*(avy-a[i].y);
}
if(fcx>=fcy){
nth_element(a+l,a+mid,a+r+1,cmp1);
divi[mid]=1;
}
else{
nth_element(a+l,a+mid,a+r+1,cmp2);
divi[mid]=2;
}
ls[mid]=build(l,mid-1);
rs[mid]=build(mid+1,r);
update(mid);
return mid;
}
ll calc(int i,int j){
return 1ll*(a[i].x-a[j].x)*(a[i].x-a[j].x)+1ll*(a[i].y-a[j].y)*(a[i].y-a[j].y);
}
ll dist(int i,int j){
ll t1=max(1ll*(a[i].x-l[j])*(a[i].x-l[j]),1ll*(a[i].x-r[j])*(a[i].x-r[j]));
ll t2=max(1ll*(a[i].y-d[j])*(a[i].y-d[j]),1ll*(a[i].y-u[j])*(a[i].y-u[j]));
return t1+t2;
}
void query(int l,int r,int x){
if(l>r)return;
int mid=(l+r)>>1;
ll t=calc(x,mid);
if(t>q.top()){
q.pop();
q.push(t);
}
ll t1=dist(x,ls[mid]),t2=dist(x,rs[mid]);
if(t1>q.top()&&t2>q.top()){
if(t1>t2){
query(l,mid-1,x);
if(t2>q.top())query(mid+1,r,x);
}
else{
query(mid+1,r,x);
if(t1>q.top())query(l,mid-1,x);
}
}
else{
if(t1>q.top())query(l,mid-1,x);
if(t2>q.top())query(mid+1,r,x);
}
}
int main() {
n=read();k=read();
k<<=1;
for(int i=1;i<=k;++i)q.push(0);
for(int i=1;i<=n;++i){
a[i].x=read();a[i].y=read();
}
build(1,n);
for(int i=1;i<=n;++i)query(1,n,i);
cout<<q.top()<<endl;
return 0;
}