4520: [Cqoi2016]K远点对
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 563 Solved: 295
[ Submit][ Status][ Discuss]
Description
已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。
Input
输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
的坐标。1 < = N < = 100000, 1 < = K < = 100, K < = N*(N−1)/2 , 0 < = X, Y < 2^31。
Output
输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。
Sample Input
10 5
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1
Sample Output
9
HINT
Source
首先我们就会观察到题目要求的k很小,加上是与空间距离有关的,很容易想到kd-tree这种算法。
我们可以考虑先枚举每个点,找到距离最远的另一些点,使得它们比目前优先队列中的最近的一些点对更远。
因为是枚举所以会算两次,k就变成了2k。
这样我们就得到了最远的2k组点对(次序不同算两组),因此最近的一组点对就是答案。
时间复杂度O(nklogk+nsqrt(n))
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
const int L=3000005;
char _buff[L]; int _pos=-1;
void ReadIn(){fread(_buff,L,sizeof(char),stdin);}
#define fge _buff[++_pos]
inline int read(){
int x=0,f=1; char ch=fge;
while(ch>'9'||ch<'0')
{if(ch=='-')f=-1;ch=fge;}
while(ch<='9'&&ch>='0')
x=x*10+ch-'0',ch=fge;
return x*f;
}
const int N=100005;
struct node{
int x[2],y[2],d[2];
void init(){
x[0]=x[1]=d[0]=read();
y[0]=y[1]=d[1]=read();
}
} p[N];
int par,n,k;
bool comp(const int&a,const int&b)
{return p[a].d[par]<p[b].d[par];}
struct KDtree{
priority_queue <ll,vector<ll>,greater<ll> > q;
int c[N][2],na[N],rt,nx,ny;KDtree(){rt=n=0;}
inline void makemx(int&x,int y){x=max(x,y);}
inline void makemn(int&x,int y){x=min(x,y);}
inline void update(int x,int y){
makemn(p[x].x[0],p[y].x[0]);
makemx(p[x].x[1],p[y].x[1]);
makemn(p[x].y[0],p[y].y[0]);
makemx(p[x].y[1],p[y].y[1]);
}
void build(int&k,int l,int r,int bas){
int mid=(l+r)>>1;par=bas;
nth_element(na+l,na+mid,na+r+1,comp);k=na[mid];
if(l<mid){
build(c[k][0],l,mid-1,bas^1);
update(k,c[k][0]);
}
if(r>mid){
build(c[k][1],mid+1,r,bas^1);
update(k,c[k][1]);
}
}
void pre(){
n=read(),k=read();int i;
for(i=1;i<=n;i++)na[i]=i,p[i].init();
for(i=1;i<=2*k;i++)q.push(0);
build(rt,1,n,0);
}
inline ll sqr (int x){return x*(ll)x;}
inline ll calc (int x){
ll sqrx=max(sqr(p[x].x[0]-nx),sqr(p[x].x[1]-nx));
ll sqry=max(sqr(p[x].y[0]-ny),sqr(p[x].y[1]-ny));
return sqrx + sqry;
}
void ask(int k){
if(k==0)return ;
ll distl=calc(c[k][0]),distr=calc(c[k][1]);
ll distn=sqr(p[k].d[0]-nx)+sqr(p[k].d[1]-ny);
if(distn>q.top())q.pop(),q.push(distn);
if(distl>distr){
if(distl>q.top()) ask(c[k][0]);
if(distr>q.top()) ask(c[k][1]);
} else {
if(distr>q.top()) ask(c[k][1]);
if(distl>q.top()) ask(c[k][0]);
}
}
void work(){
for(int i=1;i<=n;i++){
nx=p[i].d[0];
ny=p[i].d[1];
ask(rt);
}
}
} t;
int main(){
ReadIn();t.pre();t.work();
printf("%lld\n",t.q.top());
return 0;
}