题目传送门
题目大意: 给出 n n n 个点,求出其中距离第 k k k 远的点对距离。
建出K-D tree,然后造一个大小为 2 k 2k 2k 的小根堆,将每个点丢进K-D tree中跑一遍更新这个堆即可。
代码如下:
#include
#include
#include
#include
using namespace std;
#define inf 999999999999999999ll
#define maxn 100010
#define ll long long
#define zuo ch[0]
#define you ch[1]
#define pf(x) ((x)*(x))
int n,k;
priority_queue< ll,vector<ll>,greater<ll> >q;
const int K=2;
struct point{ll d[K];}a[maxn];
int C;bool cmp(point x,point y){return x.d[C]<y.d[C];}
struct KD_node *root=NULL,*null=NULL;
struct KD_node{
point x,ld,ru;
KD_node *ch[2];
KD_node(point X):x(X),ld(X),ru(X){ch[0]=ch[1]=null;}
KD_node(){}
void check(){
for(int i=0;i<K;i++){
ld.d[i]=min(ld.d[i],min(zuo->ld.d[i],you->ld.d[i]));
ru.d[i]=max(ru.d[i],max(zuo->ru.d[i],you->ru.d[i]));
}
}
ll dis_max(point X){
if(this==null)return -inf;ll re=0;
for(int i=0;i<K;i++)re+=pf(max( abs(X.d[i]-ld.d[i]) , abs(X.d[i]-ru.d[i]) ));
return re;
}
};
void init(){
null=new KD_node();
for(int i=0;i<K;i++){
null->ld.d[i]=inf;
null->ru.d[i]=-inf;
}
}
void build_KDtr(KD_node *&now,int l,int r,int CO=0)
{
if(l>=r)return;
int mid=l+r>>1;
C=CO;nth_element(a+l,a+mid,a+r,cmp);
now=new KD_node(a[mid]);
build_KDtr(now->zuo,l,mid,(CO+1)%K);
build_KDtr(now->you,mid+1,r,(CO+1)%K);
now->check();
}
ll dis(point x,point y){
ll re=0;
for(int i=0;i<K;i++)re+=pf(x.d[i]-y.d[i]);
return re;
}
void go(KD_node *now,point x)
{
if(now==null)return;
ll c=q.top();q.pop();
c=max(c,dis(now->x,x));q.push(c);
ll dis[2]={ now->zuo->dis_max(x) , now->you->dis_max(x) },to=(dis[0]>dis[1])^1;
if(dis[to]>q.top())go(now->ch[to],x);
if(dis[to^1]>q.top())go(now->ch[to^1],x);
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=2*k;i++)q.push(-inf);
for(int i=1;i<=n;i++){
for(int j=0;j<K;j++)
scanf("%lld",&a[i].d[j]);
}
init();build_KDtr(root,1,n+1);
for(int i=1;i<=n;i++)go(root,a[i]);
printf("%lld",q.top());
}