[BZOJ4520][CQOI2016] K远点对 - KD-tree

4520: [Cqoi2016]K远点对

Time Limit: 30 Sec   Memory Limit: 512 MB
Submit: 563   Solved: 295
[ Submit][ Status][ Discuss]

Description

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

Input

输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
的坐标。1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31。

Output

输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。

Sample Input

10 5
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1

Sample Output

9

HINT

Source

[ Submit][ Status][ Discuss]


首先我们就会观察到题目要求的k很小,加上是与空间距离有关的,很容易想到kd-tree这种算法。

我们可以考虑先枚举每个点,找到距离最远的另一些点,使得它们比目前优先队列中的最近的一些点对更远。

因为是枚举所以会算两次,k就变成了2k。

这样我们就得到了最远的2k组点对(次序不同算两组),因此最近的一组点对就是答案。

时间复杂度O(nklogk+nsqrt(n))

#include"bits/stdc++.h"
using namespace std;
  
typedef long long ll;
const int L=3000005;
char _buff[L]; int _pos=-1;
void ReadIn(){fread(_buff,L,sizeof(char),stdin);}
#define fge _buff[++_pos]
inline int read(){
    int x=0,f=1; char ch=fge;
    while(ch>'9'||ch<'0')
    {if(ch=='-')f=-1;ch=fge;}
    while(ch<='9'&&ch>='0')
        x=x*10+ch-'0',ch=fge;
    return x*f;
}
  
const int N=100005;
  
struct node{
    int x[2],y[2],d[2];
    void init(){
        x[0]=x[1]=d[0]=read();
        y[0]=y[1]=d[1]=read();
    }
} p[N];
int par,n,k;
bool comp(const int&a,const int&b)
{return p[a].d[par],greater > q;
    int c[N][2],na[N],rt,nx,ny;KDtree(){rt=n=0;}
    inline void makemx(int&x,int y){x=max(x,y);}
    inline void makemn(int&x,int y){x=min(x,y);}
    inline void update(int x,int y){
        makemn(p[x].x[0],p[y].x[0]);
        makemx(p[x].x[1],p[y].x[1]);
        makemn(p[x].y[0],p[y].y[0]);
        makemx(p[x].y[1],p[y].y[1]);
    }
    void build(int&k,int l,int r,int bas){
        int mid=(l+r)>>1;par=bas;
        nth_element(na+l,na+mid,na+r+1,comp);k=na[mid];
        if(lmid){
            build(c[k][1],mid+1,r,bas^1);
            update(k,c[k][1]);
        }
    }
    void pre(){
        n=read(),k=read();int i;
        for(i=1;i<=n;i++)na[i]=i,p[i].init();
        for(i=1;i<=2*k;i++)q.push(0);
        build(rt,1,n,0);
    }
    inline ll sqr (int x){return x*(ll)x;}
    inline ll calc (int x){
        ll sqrx=max(sqr(p[x].x[0]-nx),sqr(p[x].x[1]-nx));
        ll sqry=max(sqr(p[x].y[0]-ny),sqr(p[x].y[1]-ny));
        return sqrx + sqry;
    }
    void ask(int k){
        if(k==0)return ;
        ll distl=calc(c[k][0]),distr=calc(c[k][1]);
        ll distn=sqr(p[k].d[0]-nx)+sqr(p[k].d[1]-ny);
        if(distn>q.top())q.pop(),q.push(distn);
        if(distl>distr){
            if(distl>q.top()) ask(c[k][0]);
            if(distr>q.top()) ask(c[k][1]);
        } else {
            if(distr>q.top()) ask(c[k][1]);
            if(distl>q.top()) ask(c[k][0]);
        }
    }
    void work(){
        for(int i=1;i<=n;i++){
            nx=p[i].d[0];
            ny=p[i].d[1];
            ask(rt);
        }
    }
} t;
  
int main(){
    ReadIn();t.pre();t.work();
    printf("%lld\n",t.q.top());
    return 0;
}


你可能感兴趣的:(数据结构)