洛谷4357 & BZOJ4520:[CQOI2016]K远点对——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4520

https://www.luogu.com.cn/problem/P4357

已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。

KDTREE板子题?

开个堆维护前2k个最远值(因为我们之后运算的时候每个点对肯定会被算两次,所以我们最终求得第2k最远值才是答案)

就拿每个点在KDTREE上走一圈就好了……

剩余的看代码吧……(其实板子代码从某PPT里抄的怕不是看起来会非常熟悉)

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int K=2;
const int N=1e5+5;
const ll INF=1e18;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int D,n,k,root;
struct Point{
    int d[K];
    bool operator <(const Point &a)const{
        return d[D]<a.d[D];
    }
}a[N];
struct KDTREE{
    int d[K],s[2],x[2],y[2];
}tr[N];
priority_queue<ll,vector<ll>,greater<ll> >q;
#define ls tr[o].s[0]
#define rs tr[o].s[1]
#define cmax(a,b) (a<b?a=b:a)
#define cmin(a,b) (a>b?a=b:a)
void upd(int f,int x){
    cmin(tr[f].x[0],tr[x].x[0]),cmax(tr[f].x[1],tr[x].x[1]);
    cmin(tr[f].y[0],tr[x].y[0]),cmax(tr[f].y[1],tr[x].y[1]);
}
int build(int l,int r,int d){
    D=d;int o=(l+r)>>1;
    nth_element(a+l,a+o,a+r+1);
    tr[o].d[0]=tr[o].x[0]=tr[o].x[1]=a[o].d[0];
    tr[o].d[1]=tr[o].y[0]=tr[o].y[1]=a[o].d[1];
    if(l<o)ls=build(l,o-1,d^1),upd(o,ls);
    if(o<r)rs=build(o+1,r,d^1),upd(o,rs);
    return o;
}
inline ll sqr(ll x){return x*x;}
inline ll h(int o,Point p){
    return max(sqr(p.d[0]-tr[o].x[0]),sqr(p.d[0]-tr[o].x[1]))
            +max(sqr(p.d[1]-tr[o].y[0]),sqr(p.d[1]-tr[o].y[1]));
}
void query(int o,Point p){
    ll tmp=sqr(tr[o].d[0]-p.d[0])+sqr(tr[o].d[1]-p.d[1]),d[2];
    if(ls)d[0]=h(ls,p);else d[0]=-INF;
    if(rs)d[1]=h(rs,p);else d[1]=-INF;
    if(q.top()<tmp){q.pop();q.push(tmp);}
    int op=d[0]<=d[1];
    if(q.top()<d[op])query(tr[o].s[op],p);op^=1;
    if(q.top()<d[op])query(tr[o].s[op],p);
}
int main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++){
        a[i].d[0]=read(),a[i].d[1]=read();
    }
    root=build(1,n,0);
    for(int i=1;i<=2*k;i++)q.push(0);
    for(int i=1;i<=n;i++)query(root,a[i]);
    printf("%lld\n",q.top());
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2020-02-08 17:32  luyouqi233  阅读(222)  评论(0编辑  收藏  举报