zoukankan      html  css  js  c++  java
  • LibreOJ2043

    Portal

    Description

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

    Solution

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

    Code

    //「CQOI2016」K 远点对
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    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'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    const int N=1e5+10;
    const int INF=0x3FFFFFFF;
    int n,k;
    int rt,ch[N][2];
    struct point{int c[2];} pt[N];
    struct zone{int c1[2],c2[2];} zn[N];
    void update(int p)
    {
        int ch0=ch[p][0],ch1=ch[p][1];
        for(int k=0;k<2;k++)
            zn[p].c1[k]=min(pt[p].c[k],min(zn[ch0].c1[k],zn[ch1].c1[k])),
            zn[p].c2[k]=max(pt[p].c[k],max(zn[ch0].c2[k],zn[ch1].c2[k]));
    }
    int D;
    bool operator<(point A,point B) {return A.c[D]<B.c[D];}
    void bldTr(int &p,int L,int R)
    {
        if(L>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<lint>,greater<lint> > 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
    ",Q.top());
        return 0;
    }
    

    P.S.

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

  • 相关阅读:
    git 合并两个仓库
    git 合并两个仓库
    操作系统
    域名
    域名
    .NET Framework基本概念
    .NET Framework基本概念
    拓扑排序
    PHP 数组
    PHP Switch 语句
  • 原文地址:https://www.cnblogs.com/VisJiao/p/LOJ2043.html
Copyright © 2011-2022 走看看