k-D Tree 模板题
给出平面上 n(n⩽100000) 个点,求出第 K 远点对欧式距离的平方。
建 k−DTree ,对每个点求前若干远点,用一个 size 为 2K 的 priority_queue 维护(因为每对点会被算两次),最后 top() 就是答案。
需要注意的是因为越远越优,所以 get() 求的并非查询点到子树的“距离”而是到子树边界的“距离”(一己拙见)。
#include
#include
#include
#include
using namespace std;
#define Re return
#define In inline
#define St static
#define Op operator
#define inc(l, i, r) for(i=l; i
typedef long long ll;
const ll mxn=1<<17, inf=~0llu>>1;
ll n, m, D;
In ll sqr(ll a){Re a*a;}
struct node
{
ll x[2], s[2], mn[2], mx[2];//from left to right: coordinates; sons; 4 borders
node(ll x=0, ll y=0): x({x, y}), s(), mn({x, y}), mx({x, y}) {}
In bool Op<(const node& a) const
{Re x[D]//to 'nth_element' in dimensions
In ll Op-(const node& a)
{Re sqr(x[0]-a.x[0])+sqr(x[1]-a.x[1]);}/square distance
} a[mxn];
#define fxy(i) inc(0, i, 2)
In void mne(ll& a, ll b){a>b? a=b: 0;}
In void mxe(ll& a, ll b){a0;}
struct KDT
{
priority_queuevector, greater > q;
node t[mxn], T;
In void upd(ll u)//update borders
{
St ll i, j, S;
fxy(i) if(S=u[t].s[i]) fxy(j)
mne(u[t].mn[j], S[t].mn[j]),
mxe(u[t].mx[j], S[t].mx[j]);
}
ll bui(ll l, ll r, ll d)
{
if(l>r) Re 0;
D=d; ll mid=l+r>>1;
nth_element(a+l, a+mid, a+r+1);//find midium
t[mid]=a[mid];
t[mid].s[0]=bui(l, mid-1, !d);
t[mid].s[1]=bui(mid+1, r, !d);
Re upd(mid), mid;
}
In ll get(ll u)
{
if(!u) Re 0;
St ll i, r; r=0;
fxy(i) r+=max(
sqr(T.x[i]-u[t].mx[i]),
sqr(u[t].mn[i]-T.x[i]));
Re r;
}
void que(ll u, ll d)
{
ll d0, d1;
q.push(u[t]-T), q.pop();
d0=get(u[t].s[0]), d1=get(u[t].s[1]);
#define que_(i) if(d##i>q.top()) que(u[t].s[i], !d)//search if (the circle with a (radius of (the current 'kth distance'))) touchs one son's borders
if(d0>d1){que_(0); que_(1);}
else{que_(1); que_(0);}
}
} kD;
int main()
{
ll i, x, y, root;
scanf("%lld%lld", &n, &m);
inc(1, i, n+1)
scanf("%lld%lld", &x, &y),
a[i]=node(x, y);
root=kD.bui(1, n, 0);
inc(0, i, m<<1) kD.q.push(0);
inc(1, i, n+1)
kD.T=a[i], kD.que(root, 0);
printf("%lld\n", kD.q.top());
Re 0;
}