zoukankan      html  css  js  c++  java
  • bzoj1804 [Ioi2007]Flood 洪水

    Description

    1964年的一场灾难性的洪水冲毁了萨格热布城。洪水袭来时许多建筑的墙被彻底冲毁。在这个题目中,给定了城市在洪水来袭前的简化模型,你的任务是确定洪水过后哪些墙没有被冲毁。 简化模型由平面上的N个点和W堵墙构成。每堵墙连接两个点,没有任何一堵墙通过其它点。模型具有如下性质: • 不存在两堵墙相交或者重合的情况,但是两堵墙可以在端点相连; • 每堵墙或者平行于坐标系的横轴,或者平行于坐标系的纵轴。 最开始,整个坐标平面都是干的。在零时刻,洪水将城市的外围淹没(城市的外围是指没有被墙围起来的区域)。一个小时之后,所有一边是水,一边是空气的墙在水的压力下都会倒塌。于是洪水又会吞没那些没有被完好的墙围住的区域。接下来又有一些墙面临一边是水一边是空气,将要被洪水冲毁的局面。又过了一个小时,这些墙也被冲毁了。这样的过程不断重复,直到洪水淹没整个城市。 下图给出了洪水侵袭过程的一个例子。        (图一)在零时刻,阴影的格子代表洪水区域,白色的格子代表干的区域(有空气的区域)。(图二) 一个小时之后的情况。(图三)两个小时之后,洪水淹没了整个城市,有4堵墙没有被冲毁而留了下来。  任务 给定N个点的坐标和连接这些点的W堵墙的描述,编程确定洪水过后,哪些墙会被留下来。

    Input

    输入的第一行包含一个整数N(2 ≤ N ≤ 100 000), 表示平面上的点的个数。 接下来的N行每行包含两个整数X和Y(都是0到1 000 000之间(包括0和1 000 000)的整数),表示点的坐标。所有点按照它们被给出的顺序编号为1到N。没有两个点在同一位置上。 接下来一行包含一个整数W(1 ≤ W ≤ 2N),表示墙的数目。 接下来W行每行包含两个不同的整数A和B(1≤ A ≤ N, 1 ≤ B ≤ N),表示在洪水到来前,有一堵墙连接A和B。这些墙按照它们被给出的顺序编号为1到W。

    Output

    输出的第一行包含一个整数K,表示洪水过后留下的墙的数目。 评分 有40分的测试样例,所有坐标小于等于500。 在上面的样例和另外15分的样例中,点的个数不超过500个。 中将给出一个评测结果的总结。

    将原平面图转为对偶图,边权为1,计算每个结点与外围的距离,对于每条边若两侧点到外围距离相等则此边对应的墙不会被冲毁。

    #include<cstdio>
    #include<queue>
    const int N=400005;
    int n,m;
    int x[N],y[N];
    int e[N][4];
    int id1[N][4],id2[N][4],now,ans;
    bool iso[N*2];
    int es[N*2],enx[N*2],e0[N*2],ep=2;
    void addedge(int a,int b){
        if(x[a]==x[b]){
            if(y[a]<y[b])e[a][1]=b,e[b][3]=a;
            else e[a][3]=b,e[b][1]=a;
        }else{
            if(x[a]<x[b])e[a][0]=b,e[b][2]=a;
            else e[a][2]=b,e[b][0]=a;
        }
    }
    void chk(int w){
        for(int i=0;i<4;i++)if(e[w][i]){
            if(!id1[w][i]){
                id1[w][i]=++now;
                int cs=0,c;
                int p=e[w][i],a=i+2&3;
                do{
                    id2[p][a]=now;
                    c=-1;
                    while(!e[p][a+3&3])a=a+3&3,++c;
                    cs+=c;
                    a=a+3&3;
                    id1[p][a]=now;
                    p=e[p][a];
                    a=a+2&3;
                    id2[p][a]=now;
                }while(p!=w);
                c=-1;
                while(!e[p][a+3&3])a=a+3&3,++c;
                cs+=c;
                iso[now]=cs>0;
            }
        }
    }
    int l[N*2],d[N*2];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d%d",x+i,y+i);
        scanf("%d",&m);
        for(int i=0,a,b;i<m;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        for(int i=1;i<=n;i++)chk(i);
        for(int i=1;i<=n;i++){
            for(int j=0;j<4;j++)if(e[i][j]){
                int a=id1[i][j],b=id2[i][j];
                es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
                es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
            }
        }
        std::queue<int>q;
        for(int i=1;i<=now;i++)if(iso[i])q.push(i),d[i]=1;
        while(!q.empty()){
            int w=q.front();q.pop();
            for(int i=e0[w];i;i=enx[i]){
                int u=es[i];
                if(!d[u]){
                    d[u]=1;
                    l[u]=l[w]+1;
                    q.push(u);
                }
            }
        }
        for(int i=1;i<=now;i++){
            for(int j=e0[i];j;j=enx[j]){
                if(l[i]==l[es[j]])++ans;
            }
        }
        printf("%d",ans/4);
        return 0;
    }
  • 相关阅读:
    touch:创建文件及修改文件时间戳
    stat:查看文件时间参数
    获取二维数组里面实际存有数据的行数
    Math.Atan2 方法
    c#移位运算符("<<"及">>")
    c# 一维数组和二维数组的几种定义方式<转>
    C#异常处理总结
    C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)
    WinForm窗体及其控件的自适应
    C#的WinForm窗体美化
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5427442.html
Copyright © 2011-2022 走看看