LibreOJ2043 - 「CQOI2016」K 远点对

Portal

Description

给出平面上的\(n(n\leq10^5)\)个整点,求在欧几里得距离下第\(k\)远的点对之间的距离。

Solution

k-d树+堆。
用小根堆维护当前找到的第\(k\)大,然后以堆顶元素为基准在k-d树上搜索即可。搜索到一个新值\(d\)时,将其与堆顶元素比较,若大于堆顶元素则弹出堆顶并加入\(d\)

Code

//「CQOI2016」K 远点对
#include 
#include 
#include 
typedef long long lint;
using namespace std;
inline char gc()
{
    static char now[1<<16],*s,*t;
    if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
    return *s++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'R) return;
    int mid=L+R>>1; p=mid;
    nth_element(pt+L,pt+mid,pt+R+1);
    bldTr(ch[p][0],L,mid-1),bldTr(ch[p][1],mid+1,R);
    update(p);
}
priority_queue< lint,vector,greater > Q;
point A;
lint dist(point B)
{
    lint d=0;
    for(int k=0;k<2;k++) d+=1LL*(A.c[k]-B.c[k])*(A.c[k]-B.c[k]);
    return d;
}
lint dist(zone Z)
{
    if(Z.c1[0]>Z.c2[0]) return 0;
    int d[2]; d[0]=d[1]=0;
    for(int k=0;k<2;k++) d[k]=max(abs(Z.c1[k]-A.c[k]),abs(Z.c2[k]-A.c[k]));
    return 1LL*d[0]*d[0]+1LL*d[1]*d[1];
}
void query(int p)
{
    if(!p) return;
    lint d=dist(pt[p]);
    if(d>Q.top()) Q.pop(),Q.push(d);
    lint d0=dist(zn[ch[p][0]]),d1=dist(zn[ch[p][1]]);
    if(d0>Q.top()) query(ch[p][0]);
    if(d1>Q.top()) query(ch[p][1]);
}
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;i++) pt[i].c[0]=read(),pt[i].c[1]=read();
    zn[0].c1[0]=zn[0].c1[1]=INF,zn[0].c2[0]=zn[0].c2[1]=-INF;
    bldTr(rt,1,n);
    for(int i=1;i<=k+k;i++) Q.push(0);
    for(int i=1;i<=n;i++) A=pt[i],query(rt);
    printf("%d\n",Q.top());
    return 0;
}

P.S.

网上好多题解是凸包+旋转卡壳...吓死我了∑(゚Д゚ノ)ノ

转载于:https://www.cnblogs.com/VisJiao/p/LOJ2043.html

你可能感兴趣的:(LibreOJ2043 - 「CQOI2016」K 远点对)