zoukankan      html  css  js  c++  java
  • [BalticOI 2016 day1]Park(并查集+计算几何)

    [BalticOI 2016 day1]Park(并查集+计算几何)

    题面

    在 Byteland 的首都,有一个以围墙包裹的矩形公园,其中以圆形表示游客和树。
    公园里有四个入口,分别在四个角落(1, 2, 3, 4)分别对应左下、右下、左上、右上)。游客只能从入口进出。
    游客可以在他们与公园的两邻边相切的时候进出对应的出口。游客可以在公园里自由活动但不允许与树重叠。
    给出(n)棵树和(m)个游客,你的任务是为每个游客计算,给定他们进入公园的入口,他们可以从哪个入口离开公园。

    (n leq 2000,m leq 10^5)

    分析

    我们反过来考虑,求出每两个口间可以通过的圆的半径的最大值。

    把每棵树和公园的4个边界看成点,把任意两者间可以通过的半径作为边权建图。如果图上存在一条连接两个边界的路径,使得路径上边权都$leq $游客的半径,那么游客就不能通过。具体是哪些边界取决于游客的起点和终点。

    那么我们将询问离线,并按照半径从小到大排序.同时也将边权从小到大排序。将小于当前半径( imes 2)的边加入,那么就可以根据上面的方法判断是否联通。对于每一对出入口分类讨论,建议自己画图观察。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 4000000
    #define maxm 100000
    using namespace std;
    typedef long long db;
    int n,m;
    db W,H;
    struct circle{
        db x;
        db y;
        db r;
    }c[maxn+5];
    struct edge{
        int from;
        int to;
        db len;
        friend bool operator < (edge p,edge q){
            return p.len<q.len;
        }
    }E[maxn+5];
    int esz=1;
    void add_edge(int u,int v,db w){
        esz++;
        E[esz].from=u,E[esz].to=v,E[esz].len=w;
    }
    
    struct qry{
        int id;
        int pos;
        db r;
        friend bool operator < (qry p,qry q){
            return p.r<q.r;
        }
    }q[maxm+5];
    inline db dist(db x1,db y1,db x2,db y2){
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    
    struct DSU{
        int fa[maxn+5];
        int find(int x){
            if(fa[x]==x) return x;
            else return fa[x]=find(fa[x]);
        }
        inline void merge(int x,int y){
            fa[find(x)]=find(y);
        }
        inline void ini(int n){
            for(int i=1;i<=n;i++) fa[i]=i;
        }
    }S;
    
    inline bool ok(int x,int y){
        //不能通过,即两个边界对应的点被中间长度>2r边连通 
        //能通过反之 
        return S.find(n+x)!=S.find(n+y);
    }
    int ans[maxn+5][5];
    int main(){
    #ifndef LOCAL
        freopen("corner.in","r",stdin);
        freopen("corner.out","w",stdout);
    #endif
        scanf("%d %d %lld %lld",&n,&m,&W,&H);
        for(int i=1;i<=n;i++) scanf("%lld %lld %lld",&c[i].x,&c[i].y,&c[i].r);
        for(int i=1;i<=m;i++){
            scanf("%lld %d",&q[i].r,&q[i].pos);
            q[i].id=i;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                add_edge(i,j,dist(c[i].x,c[i].y,c[j].x,c[j].y)-c[i].r-c[j].r);
            }
            add_edge(i,n+1,c[i].x-c[i].r);//n+1,n+2,n+3,n+4 ->左,下,右,上 
            add_edge(i,n+2,c[i].y-c[i].r);
            add_edge(i,n+3,W-c[i].x-c[i].r);
            add_edge(i,n+4,H-c[i].y-c[i].r);
        }
        S.ini(n+4);
        sort(E+1,E+1+esz);
        sort(q+1,q+1+m);
        int ptr=0;
        for(int i=1;i<=m;i++){
            while(ptr<esz&&E[ptr+1].len<q[i].r*2){
                ptr++;
                S.merge(E[ptr].from,E[ptr].to);
            }
            int id=q[i].id,pos=q[i].pos;
            ans[id][pos]=1;
            if(pos==1){
                if(ok(1,2)&&ok(2,4)&&ok(2,3)) ans[id][2]=1;
                if(ok(1,2)&&ok(2,4)&&ok(1,3)&&ok(3,4)) ans[id][3]=1;
                if(ok(1,2)&&ok(1,3)&&ok(1,4)) ans[id][4]=1;
            }else if(pos==2){
                if(ok(1,2)&&ok(2,3)&&ok(2,4)) ans[id][1]=1;
                if(ok(2,3)&&ok(1,3)&&ok(3,4)) ans[id][3]=1;
                if(ok(2,3)&&ok(1,3)&&ok(2,4)&&ok(1,4)) ans[id][4]=1;
            }else if(pos==3){
                if(ok(3,4)&&ok(1,3)&&ok(2,4)&&ok(1,2)) ans[id][1]=1;
                if(ok(3,4)&&ok(1,3)&&ok(2,3)) ans[id][2]=1;
                if(ok(3,4)&&ok(2,4)&&ok(1,4)) ans[id][4]=1;
            }else{
                if(ok(1,4)&&ok(1,3)&&ok(1,2)) ans[id][1]=1;
                if(ok(1,4)&&ok(2,4)&&ok(1,3)&&ok(2,3)) ans[id][2]=1;
                if(ok(1,4)&&ok(2,4)&&ok(3,4)) ans[id][3]=1;
            }
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=4;j++) if(ans[i][j]) printf("%d",j);
            printf("
    ");
        }
    }
    
  • 相关阅读:
    实验-继承&super.doc
    Python库
    Github高级搜索
    代码报错记录
    编程问题解决
    百科
    【Android】添加依赖包
    【Android】导航栏(加图片icon)和不同页面的实现(viewpager+tablayout)
    【Android】Android Studio真机调试的问题统整
    【AD】自己画板的备忘
  • 原文地址:https://www.cnblogs.com/birchtree/p/14061574.html
Copyright © 2011-2022 走看看