您的位置:首页 > 其它

【BZOJ-4520】K远点对 KD-Tree + 堆

2016-05-24 19:57 267 查看

4520: [Cqoi2016]K远点对

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 490 Solved: 237
[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

Sample Output

9

HINT

Source

Solution

正解似乎是维护凸包!@#%……

不过KD Tree暴力搞就可以了,而且实测效率很高

具体的做法就是:先将平面上的所有点加入KDTree中,然后维护一个小根堆,枚举每个点进行询问

小根堆的用途及相当于当前最优解为小根堆的堆顶

Attention:

有些点会被计算两次,所以堆中实际是2*k个元素

注意开longlong,极限值的取值

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
long long read()
{
long long x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define maxn 100010
#define inf 100000000000000000LL
int n,k,D;
long long sqr(long long a) {return (long long)(a*a);}
struct PointNode
{
int l,r; long long d[2],maxx[2],minn[2];
bool operator < (const PointNode & A) const {return d[D]<A.d[D];}
PointNode (long long x=0,long long y=0) {l=r=0; d[0]=x; d[1]=y;}
}p[maxn];
priority_queue<long long, vector<long long>, greater<long long> > heap;
long long dis(PointNode A,PointNode B) {return sqr(A.d[1]-B.d[1])+sqr(A.d[0]-B.d[0]);}
struct KDTreeNode
{
int rt;
PointNode Point,tree[maxn<<1];
void Update(int now)
{
for (int i=0; i<=1; i++)
{
tree[now].minn[i]=tree[now].maxx[i]=tree[now].d[i];
if (tree[now].l)
tree[now].minn[i]=min(tree[tree[now].l].minn[i],tree[now].minn[i]),tree[now].maxx[i]=max(tree[tree[now].l].maxx[i],tree[now].maxx[i]);
if (tree[now].r)
tree[now].minn[i]=min(tree[tree[now].r].minn[i],tree[now].minn[i]),tree[now].maxx[i]=max(tree[tree[now].r].maxx[i],tree[now].maxx[i]);
}
}
int BuildTree(int l,int r,int dd)
{
int mid=(l+r)>>1;
D=dd; nth_element(p+l,p+mid,p+r+1);
tree[mid]=p[mid];
for (int i=0; i<=1; i++) tree[mid].minn[i]=tree[mid].maxx[i]=tree[mid].d[i];
if (l<mid) tree[mid].l=BuildTree(l,mid-1,dd^1);
if (r>mid) tree[mid].r=BuildTree(mid+1,r,dd^1);
Update(mid);
return mid;
}
long long dist(int pl,PointNode P)
{
long long re=0;
for (int i=0; i<=1; i++)
re+=max(sqr(P.d[i]-tree[pl].minn[i]),sqr(P.d[i]-tree[pl].maxx[i]));
return re;
}
void Query(int now)
{
long long dl,dr,d0;
d0=dis(tree[now],Point);
if (d0>heap.top()) heap.pop(),heap.push(d0);
if (tree[now].l) dl=dist(tree[now].l,Point); else dl=-inf;
if (tree[now].r) dr=dist(tree[now].r,Point); else dr=-inf;
if (dl>dr)
{
if (dl>heap.top()) Query(tree[now].l);
if (dr>heap.top()) Query(tree[now].r);
}
else
{
if (dr>heap.top()) Query(tree[now].r);
if (dl>heap.top()) Query(tree[now].l);
}
}
}KDTree;
int main()
{
//    freopen("farthest.in","r",stdin);
//    freopen("farthest.out","w",stdout);
n=read(); k=read();
for (int x,y,i=1; i<=n; i++) x=read(),y=read(),p[i]=PointNode(x,y);
KDTree.rt=KDTree.BuildTree(1,n,0);
for (int i=1; i<=k+k; i++) heap.push(0LL);
for (int i=1; i<=n; i++)
KDTree.Point=p[i],KDTree.Query(KDTree.rt);
printf("%lld\n",heap.top());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: