【BZOJ4520】K远点对(KD-Tree)

【BZOJ4520】K远点对(KD-Tree)

题面

BZOJ
洛谷

题解

考虑暴力。
维护一个大小为\(K\)的小根堆,然后每次把两个点之间的距离插进去,然后弹出堆顶

这样子可以用\(KD-Tree\)优化:
如果当前平面内可以产生的最远距离小于堆顶,则证明这个平面内的点无法产生贡献
就不需要计算了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
#define sqr(x) (1ll*(x)*(x))
#define cmin(a,b) (a>b?a=b:a)
#define cmax(a,b) (a<b?a=b:a)
#define ls (t[o].ch[0])
#define rs (t[o].ch[1])
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int D,n,K,rt;
struct Node{ll d[2];}a[MAX];
bool operator<(Node a,Node b){return a.d[D]<b.d[D];}
struct KD_Node{int mn[2],mx[2],ch[2];Node a;}t[MAX];
priority_queue<ll,vector<ll>,greater<ll> >Q;
void update(int x,int y)
{
	cmin(t[x].mn[0],t[y].mn[0]);cmin(t[x].mn[1],t[y].mn[1]);
	cmax(t[x].mx[0],t[y].mx[0]);cmax(t[x].mx[1],t[y].mx[1]);
}
int Build(int l,int r,int d)
{
	D=d;int o=(l+r)>>1;
	nth_element(&a[l],&a[o],&a[r+1]);
	t[o].mn[0]=t[o].mx[0]=t[o].a.d[0]=a[o].d[0];
	t[o].mn[1]=t[o].mx[1]=t[o].a.d[1]=a[o].d[1];
	if(l<o)ls=Build(l,o-1,d^1),update(o,ls);
	if(o<r)rs=Build(o+1,r,d^1),update(o,rs);
	return o;
}
ll Dis(Node a,Node b){return sqr(a.d[0]-b.d[0])+sqr(a.d[1]-b.d[1]);}
ll Dis(Node a,KD_Node b)
{
	ll ret=0;
	ret=max(ret,Dis(a,(Node){b.mn[0],b.mn[1]}));
	ret=max(ret,Dis(a,(Node){b.mn[0],b.mx[1]}));
	ret=max(ret,Dis(a,(Node){b.mx[0],b.mn[1]}));
	ret=max(ret,Dis(a,(Node){b.mx[0],b.mx[1]}));
	return ret;
}
void Query(int o,Node a)
{
	ll dis=Dis(a,t[o].a);
	if(dis>Q.top())Q.pop(),Q.push(dis);
	if(ls){dis=Dis(a,t[ls]);if(dis>Q.top())Query(ls,a);}
	if(rs){dis=Dis(a,t[rs]);if(dis>Q.top())Query(rs,a);}
}
int main()
{
	n=read();K=read();
	for(int i=1;i<=n;++i)a[i].d[0]=read(),a[i].d[1]=read();
	rt=Build(1,n,0);
	for(int i=1;i<=K+K;++i)Q.push(0);
	for(int i=1;i<=n;++i)Query(rt,a[i]);
	printf("%lld\n",Q.top());
	return 0;
}

posted @ 2018-05-23 15:44  小蒟蒻yyb  阅读(353)  评论(2编辑  收藏  举报