1. 程式人生 > >BZOJ4520:[CQOI2016]K遠點對

BZOJ4520:[CQOI2016]K遠點對

algo pri html log print n) != swap wap

淺談\(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遠點對