题意
给出n个矩形的左下角和右上角的坐标,计算总的面积(相交部分只算一次)。
分析
线段树扫描线的模板题。
将每个矩形都拆成上下两条线段,然后从下网上扫,当遇到底边时就加上这个区间,遇到顶边时,就减去这个区间。这些都很好理解,但是有一个点我感觉很难受!对于普通线段树,先将区间[1,2]+1,再更新区间[2,3]+1的话,2这个点的值应该是2。但是扫描线来说,2应该是1。因为[1,3]是一条线。我们的解决办法是,在线段树[L,R]的区间内储存[L,R+1]的值。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=200; 8 struct Node{ 9 double l,r,h; 10 int state; 11 bool operator <(const Node & rhs)const{ 12 return h<rhs.h; 13 } 14 Node (){} 15 Node (double l,double r,double h,int state):l(l),r(r),h(h),state(state){} 16 }node[maxn]; 17 double v[maxn]; 18 int n,kase; 19 double x1,y1,x2,y2,ans; 20 double sumv[4*maxn]; 21 int cover[4*maxn]; 22 23 void maintain(int o,int L,int R){ 24 if(cover[o]) 25 sumv[o]=v[R+1]-v[L]; 26 else if(L==R) 27 sumv[o]=0; 28 else 29 sumv[o]=sumv[2*o]+sumv[2*o+1]; 30 } 31 int ql,qr,vv; 32 void update(int o,int L,int R){ 33 if(ql<=L&&qr>=R){ 34 cover[o]+=vv; 35 maintain(o,L,R); 36 return ; 37 } 38 int M=L+(R-L)/2; 39 if(ql<=M)update(2*o,L,M); 40 if(qr>M)update(2*o+1,M+1,R); 41 maintain(o,L,R); 42 } 43 int main(){ 44 kase=0; 45 while(scanf("%d",&n)!=EOF&&n){ 46 int sz=0; 47 ++kase; 48 for(int i=1;i<=n;i++){ 49 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 50 node[++sz].l=x1,node[sz].r=x2,node[sz].h=y1,node[sz].state=1,v[sz]=x1; 51 node[++sz].l=x1,node[sz].r=x2,node[sz].h=y2,node[sz].state=-1,v[sz]=x2; 52 } 53 sort(node+1,node+1+sz); 54 sort(v+1,v+1+sz); 55 int N=unique(v+1,v+1+sz)-v-1; 56 memset(sumv,0,sizeof(sumv)); 57 memset(cover,0,sizeof(cover)); 58 ans=0; 59 for(int i=1;i<sz;i++){ 60 ql=lower_bound(v+1,v+1+N,node[i].l)-v,qr=lower_bound(v+1,v+1+N,node[i].r)-v-1,vv=node[i].state; 61 update(1,1,N); 62 ans+=sumv[1]*(node[i+1].h-node[i].h); 63 } 64 printf("Test case #%d ",kase); 65 printf("Total explored area: %.2f ",ans); 66 printf(" "); 67 } 68 return 0; 69 }