用优先队列维护一下最大的k个,然后和第k个比较看能否更新即可。枚举每个点直接在k-d tree里面查询,这样会造成重复就把k变成2k即可。
AC代码如下:
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
#define ll long long
#define sqr(x) (ll)(x)*(x)
using namespace std;
int n,m,dms,tx,ty,rt,h[100005];
void up(int &x,int y){ if (x<y) x=y; }
void dn(int &x,int y){ if (x>y) x=y; }
priority_queue<ll,vector<ll>,greater<ll> > q;
struct node{
int d[2],x[2],y[2],ls,rs;
void pfs(int u,int v){
d[0]=x[0]=x[1]=u; d[1]=y[0]=y[1]=v;
}
}p[100005];
bool cmp(int x,int y){ return p[x].d[dms]<p[y].d[dms]; }
struct kd_tree{
void maintain(int k,int t){
dn(p[k].x[0],p[t].x[0]); up(p[k].x[1],p[t].x[1]);
dn(p[k].y[0],p[t].y[0]); up(p[k].y[1],p[t].y[1]);
}
void build(int &k,int l,int r,int now){
int mid=(l+r)>>1; dms=now;
nth_element(h+l,h+mid,h+r+1,cmp); k=h[mid];
if (l<mid){ build(p[k].ls,l,mid-1,now^1); maintain(k,p[k].ls); }
if (mid<r){ build(p[k].rs,mid+1,r,now^1); maintain(k,p[k].rs); }
}
ll calc(int k){
return max(sqr(p[k].x[0]-tx),sqr(p[k].x[1]-tx))+max(sqr(p[k].y[0]-ty),sqr(p[k].y[1]-ty));
}
void qry(int k,int now){
ll dl=calc(p[k].ls),dr=calc(p[k].rs),dk=sqr(p[k].d[0]-tx)+sqr(p[k].d[1]-ty);
if (dk>q.top()){ q.pop(); q.push(dk); }
if (dl>dr){
if (p[k].ls && dl>q.top()) qry(p[k].ls,now^1);
if (p[k].rs && dr>q.top()) qry(p[k].rs,now^1);
} else{
if (p[k].rs && dr>q.top()) qry(p[k].rs,now^1);
if (p[k].ls && dl>q.top()) qry(p[k].ls,now^1);
}
}
}kd;
int main(){
scanf("%d%d",&n,&m); int i,x,y;
for (i=1; i<=n; i++){
h[i]=i; scanf("%d%d",&x,&y);
p[i].pfs(x,y);
}
kd.build(rt,1,n,0);
for (i=1; i<=(m<<1); i++) q.push(0);
for (i=1; i<=n; i++){
tx=p[i].d[0]; ty=p[i].d[1];
kd.qry(rt,0);
}
printf("%lld\n",q.top());
return 0;
}
by lych
2016.4.14