# 【BZOJ 4520/CQOI 2016】K远点对

k-D Tree 模板题


## 题意

<script type="math/tex" id="MathJax-Element-1">\quad</script>给出平面上 n(n100000) <script type="math/tex" id="MathJax-Element-2">n\;(n\leqslant 100000)\;</script>个点，求出第 K <script type="math/tex" id="MathJax-Element-3">K</script>远点对欧式距离的平方。

## 做法思路不存在的

<script type="math/tex" id="MathJax-Element-13">\quad</script>建 kDTree <script type="math/tex" id="MathJax-Element-14">k-D\;Tree</script>，对每个点求前若干远点，用一个 size <script type="math/tex" id="MathJax-Element-15">size</script>为 2K <script type="math/tex" id="MathJax-Element-16">2K</script>的 priority_queue <script type="math/tex" id="MathJax-Element-17">priority\_queue</script>维护(因为每对点会被算两次)，最后 top() <script type="math/tex" id="MathJax-Element-18">top()</script>就是答案。
<script type="math/tex" id="MathJax-Element-19">\quad</script>需要注意的是因为越远越优，所以 get() <script type="math/tex" id="MathJax-Element-20">get()</script>求的并非查询点到子树的“距离”而是到子树边界的“距离”(一己拙见)。

## Codeisthefirstpriority <script type="math/tex" id="MathJax-Element-12">Code\;is\;the\;first\;priority</script>

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

#define Re return
#define In inline
#define St static
#define Op operator
#define inc(l, i, r) for(i=l; i<r; ++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]<a.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){a<b? a=b: 0;}

struct KDT
{
priority_queue<ll, vector<ll>, greater<ll> > 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;
}

04-12 986
06-09 2697

05-13 731
07-12 654
01-14 230
01-12 121
05-30 95
09-04 34
04-24 652