kdt 0pts 求助/kel

P1429 平面最近点对(加强版)

parallet @ 2021-10-17 19:31:26

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN(2e5+10);
int n;
struct node{double x,y;};
node p[MAXN];
inline bool cmp1(node x,node y){return x.x<y.x;}//按照 x 维度划分,重写 cmp
inline bool cmp2(node x,node y){return x.y<y.y;}//按照 y 维度划分,重写 cmp  
template<class T>
inline T Min(T x,T y){return x<y?x:y;}
template<class T>
inline T Max(T x,T y){return x>y?x:y;}
double ans(1e9);
struct KD_Tree
{
    bool type[MAXN];//0 维度为 x;1 维度为 y
    int lc[MAXN],rc[MAXN];//左孩子和右孩子 
    double minx[MAXN],miny[MAXN],maxx[MAXN],maxy[MAXN];
    inline void push_up(int u)//维护 x,y 的最大最小值 
    {
        minx[u]=maxx[u]=p[u].x,miny[u]=maxy[u]=p[u].y;
        if(lc[u])
        {
            minx[u]=Min(minx[u],minx[lc[u]]);
            miny[u]=Min(miny[u],miny[lc[u]]);
            maxx[u]=Max(maxx[u],maxx[lc[u]]);
            maxy[u]=Max(maxy[u],maxy[lc[u]]);
        }
        else
        {
            minx[u]=Min(minx[u],minx[rc[u]]);
            miny[u]=Min(miny[u],miny[rc[u]]);
            maxx[u]=Max(maxx[u],maxx[rc[u]]);
            maxy[u]=Max(maxy[u],maxy[rc[u]]);
        }
        return;
    }
    inline int build(int l,int r)//建树,返回值是这个子树中的根节点编号 
    {
        if(l>=r) return 0;
        int mid=(l+r)>>1;
        double avex(0),avey(0);//计算方差所需要的平均值 
        double sx(0),sy(0);//方差 
        for(register int i=l;i<=r;i++)
            avex+=p[i].x,avey+=p[i].y;
        avex/=(double)(r-l+1),avey/=(double)(r-l+1);//计算平均值
        for(register int i=l;i<=r;i++)
            sx+=(p[i].x-avex)*(p[i].x-avex),sy+=(p[i].y-avey)*(p[i].y-avey);
            //计算 x,y 两个维度的方差 
        if(sx>=sy)//对于方差大的维度进行划分 
        {
            type[mid]=false;
            nth_element(p+l,p+mid,p+r+1,cmp1);
        }
        else
        {
            type[mid]=true;
            nth_element(p+l,p+mid,p+r+1,cmp2);
        }
        lc[mid]=build(l,mid),rc[mid]=build(mid+1,r);
        push_up(mid);//维护子树内信息,不同题目不同分析 
        return mid; 
    } 
    inline double predic(int u,node pt)
    {
        double res(0);
        if(minx[u]>pt.x) res+=(minx[u]-pt.x)*(minx[u]-pt.x);
        if(maxx[u]<pt.x) res+=(maxx[u]-pt.x)*(maxx[u]-pt.y);
        if(miny[u]>pt.y) res+=(miny[u]-pt.y)*(miny[u]-pt.y);
        if(maxy[u]<pt.y) res+=(maxy[u]-pt.y)*(maxy[u]-pt.y);
        return res; 
    }
    inline double dis(node x,node y){return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y);}
    inline void query(int l,int r,node pt,int idx)
    {
        if(l>r) return;
        int mid=(l+r)>>1;
        if(mid!=idx) ans=Min(ans,dis(pt,p[mid]));
        if(l==r) return;
        double dl=predic(lc[mid],pt),dr=predic(rc[mid],pt);
        if(dl<ans&&dr<ans)
        {
            if(dl<ans)
            {
                query(l,mid,pt,idx);
                if(dr<ans) query(mid+1,r,pt,idx);
            }
            else
            {
                query(mid+1,r,pt,idx);
                if(dl<ans) query(l,mid,pt,idx);
            }
        }
        else
        {
            if(dl<ans) query(l,mid,pt,idx);
            else query(mid+1,r,pt,idx);
        }
    }
};
KD_Tree kdt;
int main()
{
//  freopen("in1.txt","r",stdin); 
    scanf("%d",&n);
    for(register int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    kdt.build(1,n);
    for(register int i=1;i<=n;i++)
        kdt.query(1,n,p[i],i);
    printf("%.4lf\n",ans);
    return 0;
}

|