KD树 CQOI 2016 K 远点对

Description

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

分析:
维护一个存有当前2k远距离的堆(最开始全部是0)。建一个KD树,每个点查询一次,更新堆即可。对于KD树的每个节点,存储Max[],Min[],存下子树中每一维的最值,用来查询时剪枝。
代码:

#include 
#include 
#include 
#include 
#include 

#define LL long long

using namespace std;
const int maxn= 100000+5;

int n,k,curd;
priority_queue< LL , vector , greater  > Q;

template <typename T>
inline void _read(T &x){
    char ch=getchar(); bool mark=false;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
    for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    if(mark)x=-x;
}

inline LL sq(int x){return 1ll*x*x;}

struct Point {
    int x[2];
    int Max[2],Min[2];
    void init(){
        _read(x[0]); _read(x[1]); 
        Max[0]=Min[0]=x[0]; Max[1]=Min[1]=x[1];
    }
    bool operator < (const Point p)const {
        return x[curd]return sq(x[0]-A.x[0])+sq(x[1]-A.x[1]);}
}P[maxn];

void Maintain(int o,int L,int R){
    int mid= (L+R)>>1;
    int ls= (L+mid-1)>>1;
    int rs= (mid+1+R)>>1;
    for(int i=0;i<2;i++){
        if(L<=mid-1){
            P[o].Max[i]= max(P[o].Max[i],P[ls].Max[i]);
            P[o].Min[i]= min(P[o].Min[i],P[ls].Min[i]);
        }
        if(mid+1<=R){
            P[o].Max[i]= max(P[o].Max[i],P[rs].Max[i]);
            P[o].Min[i]= min(P[o].Min[i],P[rs].Min[i]);
        }
    }
}

void Build(int L,int R,int dep){
    if(L>R) return ;
    curd= (dep&1);
    int mid= (L+R)>>1;
    nth_element(P+L,P+mid,P+R+1);
    Build(L,mid-1,dep+1); Build(mid+1,R,dep+1);
    Maintain(mid,L,R);
}

LL MaxDist(int i,int o){
    LL x= max(abs(P[i].x[0]-P[o].Min[0]),abs(P[i].x[0]-P[o].Max[0]));
    LL y= max(abs(P[i].x[1]-P[o].Min[1]),abs(P[i].x[1]-P[o].Max[1]));
    return sq(x)+sq(y);
}

inline void UpdateHeap(LL d){
    if(Q.size()else if(Q.top()void Check(int i,int L,int R,int dep){
    if(L>R) return ;
    int mid= (L+R)>>1;
    int ls= (L+mid-1)>>1;
    int rs= (mid+1+R)>>1;
    if(L>mid-1) ls=0;
    if(mid+1>R) rs=0; 
    LL d= P[i].dist(P[mid]);
    UpdateHeap(d);
    LL d1= MaxDist(i,ls), d2= MaxDist(i,rs);
    if(d1>d2){
        if(ls &&d1> Q.top()) Check(i,L,mid-1,dep+1);
        if(rs &&d2> Q.top()) Check(i,mid+1,R,dep+1);
    }
    else {
        if(rs &&d2> Q.top()) Check(i,mid+1,R,dep+1);
        if(ls &&d1> Q.top()) Check(i,L,mid-1,dep+1);
    }
}

int main(){
    int i;
    _read(n); _read(k);
    k<<=1;
    for(i=1;i<=k;i++)Q.push(0);
    for(i=1;i<=n;i++)P[i].init();
    Build(1,n,0);
    for(i=1;i<=n;i++) Check(i,1,n,0);
    cout<//while(Q.size()) {cout<
    return 0;
}

你可能感兴趣的:(树,计算几何)