bzoj1804 [Ioi2007]Flood 洪水

Description

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