首页 > 其他 > 详细

BZOJ4520:[CQOI2016]K远点对

时间:2019-02-21 19:45:10      阅读:170      评论:0      收藏:0      [点我收藏+]

浅谈\(K-D\) \(Tree\)https://www.cnblogs.com/AKMer/p/10387266.html

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=4520

说实话,写了这个题之后我才明白\(K-D\) \(Tree\)最优美的地方。

那就是剪枝。

用堆维护前\(2k\)远的点对,如果当前子树内里询问点最远的距离都比堆顶小那么就直接退出。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
#define sqr(x) (1ll*(x)*(x))

const int maxn=1e5+5,inf=2147483647;

int n,k,pps,X,Y;

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct heap {
    int tot;
    ll tree[maxn];

    void ins(ll v) {
        tree[++tot]=v;int pos=tot;
        while(pos>1) {
            if(tree[pos]<tree[pos>>1])
                swap(tree[pos],tree[pos>>1]),pos>>=1;
            else break;
        }
    }

    void pop() {
        tree[1]=tree[tot--];
        int pos=1,son=2;
        while(son<=tot) {
            if(son<tot&&tree[son|1]<tree[son])son|=1;
            if(tree[son]<tree[pos])
                swap(tree[pos],tree[son]),pos=son,son=pos<<1;
            else break;
        }
    }
}H;

struct kd_tree {
    int root;

    struct point {
        int ls,rs;
        int c[2],mn[2],mx[2];

        bool operator<(const point &a)const {
            return c[pps]<a.c[pps];
        }
    }p[maxn];

    int build(int l,int r,int d) {
        int mid=(l+r)>>1,u=mid;pps=d;
        nth_element(p+l,p+mid,p+r+1);
        if(l<mid)p[u].ls=build(l,mid-1,d^1);
        if(r>mid)p[u].rs=build(mid+1,r,d^1);
        int ls=p[u].ls,rs=p[u].rs;
        for(int i=0;i<2;i++) {
            int mn=min(p[ls].mn[i],p[rs].mn[i]);
            p[u].mn[i]=min(p[u].c[i],mn);
            int mx=max(p[ls].mx[i],p[rs].mx[i]);
            p[u].mx[i]=max(p[u].c[i],mx);
        }
        return u;
    }

    void prepare() {
        p[0].mn[0]=p[0].mn[1]=inf;
        p[0].mx[0]=p[0].mx[1]=-inf;
        for(int i=1;i<=n;i++)
            p[i].c[0]=read(),p[i].c[1]=read();
        root=build(1,n,0);
    }

    ll dis(int u) {
        ll a=max(abs((ll)p[u].mn[0]-X),abs((ll)p[u].mx[0]-X));
        ll b=max(abs((ll)p[u].mn[1]-Y),abs((ll)p[u].mx[1]-Y));
        return sqr(a)+sqr(b);
    }

    void query(int u) {
        if(!u)return;
        if(H.tot==k&&dis(u)<H.tree[1])return;
        ll dist=sqr(abs((ll)X-p[u].c[0]))+sqr(abs((ll)Y-p[u].c[1]));
        if(H.tot!=k||dist>H.tree[1]) {
            H.ins(dist);if(H.tot>k)H.pop();
        }
        ll dl=p[u].ls?dis(p[u].ls):-sqr(inf);
        ll dr=p[u].rs?dis(p[u].rs):-sqr(inf);
        if(dl>dr)query(p[u].ls),query(p[u].rs);
        else query(p[u].rs),query(p[u].ls);
    }
}T;

int main() {
    n=read(),k=read()<<1;
    T.prepare();
    for(int i=1;i<=n;i++)
        X=T.p[i].c[0],Y=T.p[i].c[1],T.query(T.root);
    printf("%lld\n",H.tree[1]);
    return 0;
}

BZOJ4520:[CQOI2016]K远点对

原文:https://www.cnblogs.com/AKMer/p/10414499.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!