[CQOI2016]K远点对(KD-Tree)

暴力的做法应该是这样的,维护大小为k的堆,每次插入两点间距离并弹出堆顶。

然后这个做法显然是可以KD-Tree优化的,建立KD-Tree,然后如果该平面内最远点小于堆顶,则直接退出。就当做是复习很久没做的KD-Tree了。

不过有一个细节要注意,求最远点对,(1,2)->(2,1)算一对,所以堆的大小应该是2*k

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
struct point{ll d[2];}a[N];
struct node{int mn[2],mx[2],lc,rc;point a;}t[N];
priority_queue<ll,vector<ll>,greater<ll> >q;
int n,m,rt,D;
bool operator<(point a,point b){return a.d[D]<b.d[D];}
void pushup(int x,int y)
{
    t[x].mn[0]=min(t[x].mn[0],t[y].mn[0]);
    t[x].mn[1]=min(t[x].mn[1],t[y].mn[1]);
    t[x].mx[0]=max(t[x].mx[0],t[y].mx[0]);
    t[x].mx[1]=max(t[x].mx[1],t[y].mx[1]);
}
void build(int&k,int l,int r,int d)
{
    k=0;
    if(l>r)return;
    D=d;
    int mid=l+r>>1;
    nth_element(a+l,a+mid,a+r+1);
    k=mid;
    t[k].mn[0]=t[k].mx[0]=t[k].a.d[0]=a[k].d[0];
    t[k].mn[1]=t[k].mx[1]=t[k].a.d[1]=a[k].d[1];
    build(t[k].lc,l,mid-1,d^1);
    if(t[k].lc)pushup(k,t[k].lc);
    build(t[k].rc,mid+1,r,d^1);
    if(t[k].rc)pushup(k,t[k].rc);
}
ll getdis(point a,point b)
{return(a.d[0]-b.d[0])*(a.d[0]-b.d[0])+(a.d[1]-b.d[1])*(a.d[1]-b.d[1]);}
ll getdis2(point a,node b)
{
    ll ret=0;
    ret=max(ret,getdis(a,(point){b.mn[0],b.mn[1]}));
    ret=max(ret,getdis(a,(point){b.mn[0],b.mx[1]}));
    ret=max(ret,getdis(a,(point){b.mx[0],b.mn[1]}));
    ret=max(ret,getdis(a,(point){b.mx[0],b.mx[1]}));
    return ret;
}
void query(int k,point a)
{
    ll dis=getdis(a,t[k].a);
    if(dis>q.top())q.pop(),q.push(dis);
    if(t[k].lc)
    {
        dis=getdis2(a,t[t[k].lc]);
        if(dis>q.top())query(t[k].lc,a);
    }
    if(t[k].rc)
    {
        dis=getdis2(a,t[t[k].rc]);
        if(dis>q.top())query(t[k].rc,a);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].d[0],&a[i].d[1]);
    build(rt,1,n,0);
    for(int i=1;i<=m*2;i++)q.push(0);
    for(int i=1;i<=n;i++)query(rt,a[i]);
    printf("%lld",q.top());
}
View Code
原文地址:https://www.cnblogs.com/hfctf0210/p/11179344.html