题目链接:http://poj.org/problem?id=1151
折腾了一下午的题...
具体解释见代码注释。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100005; int n,num; double y[maxn]; struct Line{//扫描线 double x,y1,y2; int flag; inline bool operator <(const Line a) const{ return x<a.x; } }line[maxn]; void addLine(double x1,double y1,double x2,double y2){ line[num].x=x1; line[num].y1=y1; line[num].y2=y2; line[num].flag=1;//表示矩形的左边 y[num]=y1;//因为数据较大,将所有y坐标映射到y轴上,进行离散化 num++; line[num].x=x2; line[num].y1=y1; line[num].y2=y2; line[num].flag=-1;//表示矩形的右边 y[num]=y2; num++; } struct segmentTree{ int l,r; double lf,rf; int cover;//标记是否被覆盖 double len;//记录长度 }node[3*maxn]; void build(int rt,int l,int r){ node[rt].l=l; node[rt].r=r; node[rt].lf=y[l]; node[rt].rf=y[r]; node[rt].cover=0; node[rt].len=0; if(l+1==r) return ; int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid,r); } void callen(int rt){//计算长度 if(node[rt].cover>0){//如果未覆盖,直接计算长度即可 node[rt].len=node[rt].rf-node[rt].lf; return ; } if(node[rt].l+1==node[rt].r) {node[rt].len=0;}//如果被覆盖且是叶节点,长度置为0 else node[rt].len=node[rt<<1].len+node[rt<<1|1].len;//非叶节点,从下往上更新 } void Update(int rt,Line e){ if(node[rt].lf==e.y1&&node[rt].rf==e.y2){ node[rt].cover+=e.flag; callen(rt); return ; } if(e.y2<=node[rt<<1].rf) Update(rt<<1,e); else if(e.y1>=node[rt<<1|1].lf) Update(rt<<1|1,e); else{ Line tmp1=e; tmp1.y2=node[rt<<1].rf; Update(rt<<1,tmp1); Line tmp2=e; tmp2.y1=node[rt<<1|1].lf; Update(rt<<1|1,tmp2); } callen(rt); } int main(){ #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif int Cas=1; double x1,x2,y1,y2; while(~scanf("%d",&n)&&n){ num=1; for(int i=0;i<n;i++){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); addLine(x1,y1,x2,y2); } sort(line+1,line+num); sort(y+1,y+num); build(1,1,num-1); double ans=0; for(int i=2;i<num;i++){ Update(1,line[i-1]); ans+=node[1].len*(line[i].x-line[i-1].x); } printf("Test case #%d\n",Cas++); printf("Total explored area: %.2f\n\n",ans); } return 0; }