【BZOJ 4520/CQOI 2016】K远点对

【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;
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页