【BZOJ 4520/CQOI 2016】K远点对

【BZOJ 4520/CQOI 2016】K远点对

k-D Tree 模板题

题意

给出平面上 n(n100000) 个点,求出第 K 远点对欧式距离的平方。

做法思路不存在的

kDTree ,对每个点求前若干远点,用一个 size 2K priority_queue 维护(因为每对点会被算两次),最后 top() 就是答案。
需要注意的是因为越远越优,所以 get() 求的并非查询点到子树的“距离”而是到子树边界的“距离”(一己拙见)。

Codeisthefirstpriority

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值