codevs3044 矩形面积求并 线段树+扫描线
题意:给定N个矩形,求复数个矩形所覆盖的面积和
题解:
首先我们离散化,然后按照纵坐标从下往上扫,每扫到一条边,就把这条边的边权压入线段树——规定始边边权为1,终边边权为-1
每次从下往上枚举一条边,将每两个坐标之间的间隔看成是一个点,每次枚举看那个间隔权值>1,统计下来,乘以两条边之间的距离。
当然枚举间隔的时候不必全扫一边,如果一个区间的和为零,直接return
#include <map> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100+2; struct LINE{ int t; double sx,tx,y; LINE(){} LINE(int _t,double _sx,double _tx,double _y):t(_t),sx(_sx),tx(_tx),y(_y){} }line[2*MAXN]; typedef struct NODE{ int l,r,s,add; NODE *lchild,*rchild; NODE(){} NODE(int _l,int _r):l(_l),r(_r),s(0),add(0),lchild(0),rchild(0){} } *TREE; TREE root; int N,M,b[2*MAXN]; double x1,x2,y1,y2,ans,width,a[2*MAXN],l[2*MAXN]; map<double,int> table; bool cmp1(LINE a,LINE b){ return a.y<b.y;} bool cmp2(int x,int y){ return a[x]<a[y];} void Pushup(TREE &x){ x->s=x->lchild->s+x->rchild->s;} void Pushdown(TREE &x,int m){ if(x->add){ x->lchild->s+=x->add*(m-(m>>1)); x->rchild->s+=x->add*(m>>1); x->lchild->add+=x->add,x->rchild->add+=x->add,x->add=0; } } void Build(TREE &x,int l,int r){ x=new NODE(l,r); if(l==r) return; int m=(l+r)>>1; Build(x->lchild,l,m),Build(x->rchild,m+1,r); } void Update(TREE &x,int l,int r,int v){ if(x->l>=l && x->r<=r){ x->add+=v,x->s+=v*(x->r-x->l+1); return; } Pushdown(x,x->r-x->l+1); int m=(x->l+x->r)>>1; if(l<=m) Update(x->lchild,l,r,v); if(r>m) Update(x->rchild,l,r,v); Pushup(x); } bool Query(TREE &x,int p){ if(x->l==x->r) return x->s; Pushdown(x,x->r-x->l+1); if(!x->s) return 0; int m=(x->l+x->r)>>1; if(p<=m) return Query(x->lchild,p); return Query(x->rchild,p); } void Erase(TREE &x){ if(!x) return; Erase(x->lchild),Erase(x->rchild); delete x; } int main(){ while(scanf("%d",&N)!=EOF){ if(!N) break; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(l,0,sizeof(l)); memset(line,0,sizeof(line)); table.clear(),M=0; for(int i=1;i<=N;i++){ cin >> x1 >> y1 >> x2 >> y2; line[++M]=LINE(1,x1,x2,y1),a[M]=x1,b[M]=M; line[++M]=LINE(-1,x1,x2,y2),a[M]=x2,b[M]=M; } sort(line+1,line+M+1,cmp1); sort(b+1,b+M+1,cmp2); N=0; for(int i=1,t=0;i<=M;i++) if(!t || a[b[i]]!=a[b[t]]) table[a[b[i]]]=++N,l[N]=a[b[i]]-a[b[t]],t=i; Build(root,1,N),ans=width=0; for(int i=1;i<=M;i++){ ans+=(line[i].y-line[i-1].y)*width; if(table[line[i].sx]+1<=table[line[i].tx]) Update(root,table[line[i].sx]+1,table[line[i].tx],line[i].t); width=0; for(int j=2;j<=N;j++) if(Query(root,j)) width+=l[j]; } printf("%.2lf\n",ans); Erase(root); } return 0; }