线段树+离散化+扫描线
和求矩形合并周长思路差不多
#include<cstdio> #include<algorithm> #define N 10010 using namespace std; struct Tree{ int l,r,cover; //len表示区间【l,r】被占用的总长度 double len; }tree[3*N]; struct Line{ double x,y1,y2; int flag; }l[N]; double y[N]; bool cmp(struct Line a,struct Line b){ //这里表示当2条线段x坐标重合时优先处理是入边的矩形的线段 if(a.x==b.x)return a.flag>b.flag; return a.x<b.x; } void build(int s,int t,int id){ tree[id].l=s,tree[id].r=t; tree[id].cover=0; tree[id].len=0; if(s!=t-1){ int mid=(s+t)>>1; build(s,mid,id<<1); build(mid,t,id<<1|1); } } void update(int id){ if(tree[id].cover>0) tree[id].len=y[tree[id].r-1]-y[tree[id].l-1]; //注意这里都要减一 else if(tree[id].l==tree[id].r-1) tree[id].len=0; else tree[id].len=tree[id<<1].len+tree[id<<1|1].len; } void query(int s,int t,int flag,int id){ if(tree[id].l==s && tree[id].r==t){ tree[id].cover+=flag; update(id); return; } int mid=(tree[id].l+tree[id].r)>>1; if(t<=mid)query(s,t,flag,id<<1); else if(s>=mid)query(s,t,flag,id<<1|1); else{ query(s,mid,flag,id<<1); query(mid,t,flag,id<<1|1); } update(id); } int main(){ int i,n; double x1,x2,y1,y2; int cas=0; while(scanf("%d",&n)==1){ if(n==0)break; int cnt=0; for(i=1;i<=n;i++){ scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2); l[cnt].x=x1,l[cnt].y1=y1,l[cnt].y2=y2,l[cnt].flag=1,y[cnt++]=y1; l[cnt].x=x2,l[cnt].y1=y1,l[cnt].y2=y2,l[cnt].flag=-1,y[cnt++]=y2; } sort(y,y+cnt); sort(l,l+cnt,cmp); int t=unique(y,y+cnt)-y; build(1,t,1); double ans=0,last=0; for(i=0;i<cnt;i++){ int ll=lower_bound(y,y+t,l[i].y1)-y+1; int rr=lower_bound(y,y+t,l[i].y2)-y+1; query(ll,rr,l[i].flag,1); if(i)ans+=last*(l[i].x-l[i-1].x); last=tree[1].len; } printf("Test case #%d\nTotal explored area: %.2lf\n",++cas,ans); puts(""); } return 0; }