zoukankan      html  css  js  c++  java
  • HDU 5809 Ants(KD树+并查集)

    【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5809

     

    【题目大意】

      给出一些蚂蚁和他们的巢穴,一开始他们会在自己的巢穴(以二维坐标形式给出),之后每一个时刻会向距离自己最近的巢穴移动,当两只蚂蚁相向而行的时候,我们可以认为他们相遇了,现在有q个询问,每个询问需要让你判断蚂蚁x和y是否会相遇。

    【题解】

      我们可以发现对于一只蚂蚁来说,他最后肯定会陷入一个二元环中来回走动,那么我们只要判断是否最后两只蚂蚁会出现在同一个二元环中,那么就可以判断他们是否可以相遇。

      首先对于所有点构建KD树,对于每个点计算离它最近的点,将两个点加入同一个集合,最后判断询问两点是否属于同一个集合即可,集合的合并和判断可以用并查集实现。

    【代码】

    #include <cstdio>
    #include <algorithm>
    const int N=400010;
    int n,i,id[N],root,cmp_d;
    typedef long long LL;
    const LL INF=0x3f3f3f3f3f3f3f3fLL;
    struct node{
        int d[2],l,r,Max[2],Min[2],val,sum,f,id;
        bool operator<(const node& B){return d[0]<B.d[0]||(d[0]==B.d[0]&&d[1]<B.d[1]);}
    }t[N];
    inline bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
    inline void umax(int&a,int b){if(a<b)a=b;}
    inline void umin(int&a,int b){if(a>b)a=b;}
    inline void up(int x){
        if(t[x].l){
            umax(t[x].Max[0],t[t[x].l].Max[0]);
            umin(t[x].Min[0],t[t[x].l].Min[0]);   
            umax(t[x].Max[1],t[t[x].l].Max[1]);
            umin(t[x].Min[1],t[t[x].l].Min[1]);
        }
        if(t[x].r){
            umax(t[x].Max[0],t[t[x].r].Max[0]);
            umin(t[x].Min[0],t[t[x].r].Min[0]);
            umax(t[x].Max[1],t[t[x].r].Max[1]);
            umin(t[x].Min[1],t[t[x].r].Min[1]);
        }
    }
    int build(int l,int r,int D,int f){
        int mid=(l+r)>>1;
        cmp_d=D,std::nth_element(t+l+1,t+mid+1,t+r+1,cmp);
        id[t[mid].f]=mid;
        t[mid].f=f;
        t[mid].Max[0]=t[mid].Min[0]=t[mid].d[0];
        t[mid].Max[1]=t[mid].Min[1]=t[mid].d[1];
        t[mid].val=t[mid].sum=0;
        if(l!=mid)t[mid].l=build(l,mid-1,!D,mid);else t[mid].l=0;
        if(r!=mid)t[mid].r=build(mid+1,r,!D,mid);else t[mid].r=0;
        return up(mid),mid;
    }
    inline LL sqr(int x){return (LL)x*x;}
    LL ans; node ansP;
    LL ans2; node ansP2;
    int px,py;
    inline LL dist(int p1){
        LL dis=0;
        if(px<t[p1].Min[0])dis+=sqr(t[p1].Min[0]-px);
        if(px>t[p1].Max[0])dis+=sqr(px-t[p1].Max[0]);
        if(py<t[p1].Min[1])dis+=sqr(t[p1].Min[1]-py);
        if(py>t[p1].Max[1])dis+=sqr(py-t[p1].Max[1]);
        return dis;
    }
    void ask(int x){
        LL dl,dr,d0=sqr(t[x].d[0]-px)+sqr(t[x].d[1]-py);
        if(d0<ans||(d0==ans&&t[x]<ansP))ans2=ans,ansP2=ansP,ans=d0,ansP=t[x];
        else if(d0<ans2||(d0==ans2&&t[x]<ansP2))ans2=d0,ansP2=t[x];
        dl=t[x].l?dist(t[x].l):INF;
        dr=t[x].r?dist(t[x].r):INF;
        if(dl<dr){
            if(dl<=ans2)ask(t[x].l);
            if(dr<=ans2)ask(t[x].r);
        }else{
            if(dr<=ans2)ask(t[x].r);
            if(dl<=ans2)ask(t[x].l);
        }
    }
    int getP(int root){
        ans=ans2=INF; ask(root); return ansP2.id;
    }
    int T,x,y,Cas=1,q,f[N];
    int sf(int x){return f[x]==x?f[x]:f[x]=sf(f[x]);}
    int main(){
        scanf("%d",&T);
        while(T--){
            printf("Case #%d:
    ",Cas++);
            scanf("%d%d",&n,&q);
            for(int i=1;i<=n;i++){
                scanf("%d%d",&x,&y);
                t[i].d[0]=x,t[i].d[1]=y,t[i].id=i;
            }root=build(1,n,0,0);
            for(int i=1;i<=n;i++)f[i]=i;
            for(int i=1;i<=n;i++){
                px=t[i].d[0],py=t[i].d[1];
                x=t[i].id,y=getP(root);
                f[sf(x)]=sf(y);
            }
            while(q--){
                scanf("%d%d",&x,&y);
                puts(sf(x)==sf(y)?"YES":"NO");
            }
        }return 0;
    }
  • 相关阅读:
    podfile 文件写法
    九大内置对象
    动态网页开发基础
    表单效验
    使用jQuery快速高效制作网页交互特效
    使用jQuery操作DOM
    jQuery选择器
    初始jQuery
    javaScript基础及初始面向对象
    JavaScript操作DOM对象
  • 原文地址:https://www.cnblogs.com/forever97/p/hdu5809.html
Copyright © 2011-2022 走看看