BZOJ1804: [Ioi2007]Flood 洪水
把点按坐标排序,每次找出最小的点,一定在最外层,再顺着把最外层的边删掉,经过了两次的边不会被冲毁。
#include<bits/stdc++.h> using namespace std; const int N=4e5+5; int n,m,y,q[N],x[N],e[N],*back=e,*f[N][4]; struct vec{ int x,y,z; }a[N],r[N]; bool operator<(vec u,vec v){ return u.x<v.x||u.x==v.x&&u.y<v.y; } int foo(int i,int j){ return a[i].x==a[j].x?a[i].y<a[j].y?3:1:a[i].x<a[j].x?2:0; } void add(int u,int v){ f[u][foo(u,v)]=&(*back++=v); f[v][foo(v,u)]=&(*back++=u); } bool test(int i){ for(int j=0;j!=4;++j) if(f[i][j])return 1; return 0; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ a[i].z=i; scanf("%d%d",&a[i].x,&a[i].y); r[i]=a[i]; } scanf("%d",&m); for(int i=1;i<=m;++i){ int u,v; scanf("%d%d",&u,&v); add(u,v); } sort(r+1,r+n+1); for(int i=1;i<=n;++i) while(test(r[i].z)){ int l=0,j=2,k=r[i].z; do{ j=j+3&3; while(!f[k][j]) ++j&=3; ++x[(q[l++]=f[k][j]-e)>>1]; k=*f[k][j]; }while(k!=r[i].z); for(int j=0;j!=l;++j){ int u=e[q[j]],v=e[q[j]^1]; f[u][foo(u,v)]=0; f[v][foo(v,u)]=0; } } for(int i=0;i!=m;++i) y+=x[i]==2; printf("%d\n",y); }