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 远点对的距离的平方(一定是个整数)。
Solution
K-Dtree板子?
玄学时间复杂度
维护一个小根堆 存最大2m个距离(点对会算两次)
每个点都进K-Dtree算一次
显而易见对于一个点到矩阵 必然点到矩阵的四个角的距离最大
判断最大距离是否大于堆顶或堆未达到2*m个数 若否则退出
每到一个点都判断当前点是否能入堆
一直乱搞到底就完了
Code
#include<bits/stdc++.h>
using namespace std;
const double alpha=0.7;
const int k=2;
struct pt{
int d[k],w;
}a[200010];
struct data{
int mx[k],mn[k],sum,ls,rs,sz;
pt p;
}tree[200010];
int stk[200010];
int b[200010][2],n,m;
priority_queue<long long,vector<long long>,greater<long long> >q;
int ans,tot,word,top,rt;
int operator <(pt u,pt v){
return u.d[word]<v.d[word];
}
int newnode(){
if(top) return stk[top--];
return ++tot;
}
void up(int x){
int l=tree[x].ls;
int r=tree[x].rs;
for(int i=0;i<2;i++){
tree[x].mx[i]=tree[x].mn[i]=tree[x].p.d[i];
if(l) tree[x].mx[i]=max(tree[x].mx[i],tree[l].mx[i]);
if(r) tree[x].mx[i]=max(tree[x].mx[i],tree[r].mx[i]);
if(l) tree[x].mn[i]=min(tree[x].mn[i],tree[l].mn[i]);
if(r) tree[x].mn[i]=min(tree[x].mn[i],tree[r].mn[i]);
}
tree[x].sum=tree[l].sum+tree[r].sum+tree[x].p.w;
tree[x].sz=tree[l].sz+tree[r].sz+1;
}
int build(int l,int r,int wd){
if(l>r) return 0;
int mid=(l+r)>>1;
int x=newnode();
word=wd,nth_element(a+l,a+mid,a+r+1);
tree[x].p=a[mid];
tree[x].ls=build(l,mid-1,wd^1);
tree[x].rs=build(mid+1,r,wd^1);
up(x); return x;
}
void flt(int x,int num){
int l=tree[x].ls;
int r=tree[x].rs;
if(l) flt(l,num);
stk[++top]=x;
a[tree[l].sz+num+1]=tree[x].p;
if(r) flt(r,num+tree[l].sz+1);
}
void check(int &x,int wd){
int l=tree[x].ls,r=tree[x].rs;
if(tree[x].sz*alpha<tree[l].sz||tree[x].sz*alpha<tree[r].sz)
flt(x,0),x=build(1,tree[x].sz,wd);
}
void ins(int &x,pt y,int wd){
if(x==0){
x=newnode();
tree[x].p=y;
tree[x].ls=0;
tree[x].rs=0;
up(x);
return;
}
if(y.d[wd]<=tree[x].p.d[wd]) ins(tree[x].ls,y,wd^1);
else ins(tree[x].rs,y,wd^1);
up(x),check(x,wd);
}
long long work(int x1,int y1,int x2,int y2){
return (x1-x2)*1ll*(x1-x2)+(y1-y2)*1ll*(y1-y2);
//return (abs(x1-x2)+abs(y1-y2))*1ll*(abs(x1-x2)+abs(y1-y2));
}
long long get(int x,int y,int X1,int Y1,int X2,int Y2){
return max(work(x,y,X1,Y1),max(work(x,y,X2,Y2),max(work(x,y,X1,Y2),work(x,y,X2,Y1))));
}
void query(int u,int x,int y){
//cout<<u<<" "<<x<<" "<<y<<endl;
if(u==0) return;
int l=tree[u].ls,r=tree[u].rs;
if(q.size()==2*m&&get(x,y,tree[u].mn[0],tree[u].mn[1],tree[u].mx[0],tree[u].mx[1])<=q.top()) return;
//cout<<u<<" "<<x<<" "<<y<<" "<<tree[u].p.d[0]<<" "<<tree[u].p.d[1]<<" "<<work(x,y,tree[u].p.d[0],tree[u].p.d[1])<<" "<<(q.size()?q.top():-1)<<endl;
if(q.size()<2*m||work(x,y,tree[u].p.d[0],tree[u].p.d[1])>q.top()){
if(q.size()==2*m) q.pop();
q.push(work(x,y,tree[u].p.d[0],tree[u].p.d[1]));
}
// cout<<l<<" "<<r<<endl;
if(l&&get(x,y,tree[l].mn[0],tree[l].mn[1],tree[l].mx[0],tree[l].mx[1])>get(x,y,tree[r].mn[0],tree[r].mn[1],tree[r].mx[0],tree[r].mx[1])){
if(l) query(l,x,y);
if(r) query(r,x,y);
}
else{
if(r) query(r,x,y);
if(l) query(l,x,y);
}
// cout<<"swihfdriuqw\n";
}
int main(){
int x,y;
//freopen("s.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].d[0],&a[i].d[1]);
b[i][0]=a[i].d[0],b[i][1]=a[i].d[1];
}
rt=build(1,n,0);
//for(int i=1;i<=n;i++)
//cout<<tree[i].p.d[0]<<" "<<tree[i].p.d[1]<<" "<<tree[i].ls<<" "<<tree[i].rs<<" "<<tree[i].mn[0]<<" "<<tree[i].mn[1]<<" "<<tree[i].mx[0]<<" "<<tree[i].mx[1]<<endl;
for(int i=1;i<=n;i++)
query(rt,b[i][0],b[i][1]);
printf("%lld",q.top());
//while(q.size()) printf("%lld ",q.top()),q.pop();
}