4520: [Cqoi2016]K远点对
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 628 Solved: 334
[ 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
题解:KD-tree
建立KD-tree,枚举每个节点更新答案。因为这样每个点对会被计算两次,所以将k*=2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define LL long long
#define N 200003
using namespace std;
int root,cmpd,n,m,x,y;
struct data
{
int d[2],mx[2],mn[2],l,r;
}tr[N];
priority_queue<LL,vector<LL>,greater<LL> > p;
int cmp(data a,data b)
{
return a.d[cmpd]<b.d[cmpd]||a.d[cmpd]==b.d[cmpd]&&a.d[cmpd^1]<b.d[cmpd^1];
}
void update(int now)
{
int l=tr[now].l;int r=tr[now].r;
for (int i=0;i<=1;i++){
if (l) tr[now].mx[i]=max(tr[now].mx[i],tr[l].mx[i]),
tr[now].mn[i]=min(tr[now].mn[i],tr[l].mn[i]);
if (r) tr[now].mx[i]=max(tr[now].mx[i],tr[r].mx[i]),
tr[now].mn[i]=min(tr[now].mn[i],tr[r].mn[i]);
}
}
int build(int l,int r,int d)
{
cmpd=d;
int mid=(l+r)/2;
nth_element(tr+l,tr+mid,tr+r+1,cmp);
for (int i=0;i<=1;i++)
tr[mid].mx[i]=tr[mid].mn[i]=tr[mid].d[i];
if (l<mid) tr[mid].l=build(l,mid-1,d^1);
if (r>mid) tr[mid].r=build (mid+1,r,d^1);
update(mid);
return mid;
}
LL pow(int x)
{
return (LL)x*(LL)x;
}
LL dist(int now)
{
LL t=0;
t+=max(pow(tr[now].mx[0]-x),pow(tr[now].mn[0]-x));
t+=max(pow(tr[now].mx[1]-y),pow(tr[now].mn[1]-y));
return t;
}
void query(int now)
{
LL d0=pow(tr[now].d[0]-x)+pow(tr[now].d[1]-y);
if (p.size()<m) p.push(d0);
else {
LL t=p.top();
if (d0>t) {
p.pop();
p.push(d0);
}
}
LL dl=-1,dr=-1;
if(tr[now].l) dl=dist(tr[now].l);
if(tr[now].r) dr=dist(tr[now].r);
if (dl>dr) {
if (dl!=-1)
if (p.size()<m||p.top()<dl) query(tr[now].l);
if (dr!=-1)
if (p.size()<m||p.top()<dr) query(tr[now].r);
}
else{
if (dr!=-1)
if (p.size()<m||p.top()<dr) query(tr[now].r);
if (dl!=-1)
if (p.size()<m||p.top()<dl) query(tr[now].l);
}
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d%d",&tr[i].d[0],&tr[i].d[1]);
root=build(1,n,0);
m*=2;
for (int i=1;i<=n;i++) {
x=tr[i].d[0]; y=tr[i].d[1];
query(root);
}
printf("%I64d\n",p.top());
}