扫描线求矩形重叠面积:http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html
http://www.tuicool.com/articles/6Zf6J3
这题参考:http://www.cppblog.com/menjitianya/archive/2011/03/30/143043.html
解题思路:线段树+离散化
首先我们将每个矩形的纵向边投影到Y轴上,这样就可以把矩形的纵向边看成一个闭区间,用线段树来维护这些矩形边的并。现在求的是矩形的面积并,于是可以枚举矩形的x坐标,然后检测当前相邻x坐标上y方向的合法长度,两者相乘就是其中一块面积,枚举完毕后就求得了所有矩形的面积并。 我的线段树结点描述保存了以下信息:区间的左右端点、结点所在数组编号(因为采用静态结点可以大大节省申请空间的时间)、该结点被竖直线段完全覆盖的次数Cover和当前结点覆盖一次的y方向长度yOnce和当前结点覆盖多次的y方向长度yMore。
其实和矩形面积并的唯一差别就是在计算Cover后的Update函数,更新yOnce和yMore的值,分情况讨论:
1. 当nCover>1时,yOnce = 0; yMore = 区间实际长度;
2. 当nCover=1时,yMore = 两棵子树的yOnce+yMore;
yOnce = 区间实际长度 - yMore;
3. 当nCover=0时,如果是叶子结点 yOnce = 0; yMore = 0;
否则
yOnce = 两棵子树的yOnce和;
yMore = 两棵子树的yMore和;
这题还是先要把扫描法看懂了,剩下的就好办了。
AC:
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 2200; const double eps = 1e-6; double edge[maxn],tmp[maxn]; int tmpsize,size; struct Segment { int p,l,r; int nCover; double yOne,yMore; void Update() { if(nCover > 1) { yOne = 0; yMore = edge[r] - edge[l]; } else if(nCover == 1) { yMore = tree[p<<1].yMore + tree[p<<1].yOne + tree[p<<1|1].yMore + tree[p<<1|1].yOne; yOne = edge[r] - edge[l] - yMore; } else { if(l + 1 == r) //叶子节点,无法拓展 { yOne = yMore = 0; } else { yOne = tree[p<<1].yOne + tree[p<<1|1].yOne; yMore = tree[p<<1].yMore + tree[p<<1|1].yMore; } } } }tree[maxn<<2]; struct Line { double x,y1,y2; int val; Line(){ } Line(double _x,double _y1,double _y2,double _val) { x = _x; y1 = _y1; y2 = _y2; val = _val; } }; vector<Line> vec; bool cmp(Line a, Line b) { return a.x < b.x; } void DiscretData() { sort(tmp,tmp+tmpsize); size = 0; edge[++size] = tmp[0]; for(int i = 1; i < tmpsize; i++) if(fabs(tmp[i] - tmp[i-1]) > eps) edge[++size] = tmp[i]; } void build(int o,int l,int r) { tree[o].l = l, tree[o].r = r; tree[o].nCover = tree[o].yMore = tree[o].yOne = 0; tree[o].p = o; if(l+1 == r || l == r) return; int mid = (l + r) >> 1; build(o<<1,l,mid); build(o<<1|1,mid,r); //这里不能是mid+1,因为算的是线段长度,如果是mid+1,会变成1-2和3-4的区间,中间2-3这一段就无法计算了 } void insert(int o,int l,int r,int val) { if(l <= tree[o].l && tree[o].r <= r) { tree[o].nCover += val; tree[o].Update(); return; } int mid = (tree[o].l + tree[o].r) >> 1; if(mid > l) insert(o<<1,l,r,val); if(mid < r) insert(o<<1|1,l,r,val); tree[o].Update(); } int bisearch(double x) { int l = 1,r = size,mid; while(l <= r) { mid = (l + r) >> 1; if(fabs(edge[mid] - x) < eps) return mid; else if(x > edge[mid]) l = mid + 1; else r = mid - 1; } } int main() { int t,n; cin >> t; while(t--) { cin >> n; tmpsize = 0; vec.clear(); for(int i = 1; i <= n; i++) { double x0,x1,y0,y1; cin >> x0 >> y0 >> x1 >> y1; vec.push_back(Line(x0,y0,y1,1)); vec.push_back(Line(x1,y0,y1,-1)); tmp[tmpsize++] = y0; tmp[tmpsize++] = y1; } sort(vec.begin(),vec.end(),cmp); DiscretData(); build(1,1,size); double ans = 0; for(int i = 0; i < vec.size(); i++) { if(i > 0) ans += (vec[i].x - vec[i-1].x) * tree[1].yMore; int l = bisearch(vec[i].y1); int r = bisearch(vec[i].y2); insert(1,l,r,vec[i].val); } printf("%.2lf\n",ans); } return 0; }