|
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
/**//* 题意: 给出N(N <= 1000)个矩形,求被覆盖2次以上的矩形面积并。
解法: 离散化+线段树
思路: 类似于覆盖一次的矩形面积并问题,还是用线段树求解,首先我们 将每个矩形的纵向边投影到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和; */
#include <iostream> #include <algorithm> #include <vector> #include <cmath>
using namespace std;
#define maxn 2200
double tmp[maxn], bin[maxn]; int tmpsize, size;
struct Tree { int p; int l, r; int nCover; double ylenOnce, ylenMore;
void Update() { if(nCover > 1) { ylenOnce = 0; ylenMore = bin[r] - bin[l]; }else if(nCover == 1) { ylenMore = T[p<<1].ylenMore + T[p<<1].ylenOnce + T[p<<1|1].ylenMore + T[p<<1|1].ylenOnce; ylenOnce = (bin[r] - bin[l]) - ylenMore; }else { if(l + 1 == r) { ylenOnce = ylenMore = 0; }else { ylenOnce = T[p<<1].ylenOnce + T[p<<1|1].ylenOnce; ylenMore = T[p<<1].ylenMore + T[p<<1|1].ylenMore; } } } }T[maxn*4];
struct VLine { double x; double y1, y2; int val; VLine() {} VLine(double _x, double _y1, double _y2, int _v) { x = _x; y1 = _y1; y2 = _y2; val = _v; } }; vector < VLine > Vl;
bool cmp(VLine a, VLine b) { return a.x < b.x; }
void Process() { sort(tmp, tmp + tmpsize); bin[ size = 1 ] = tmp[0]; for(int i = 1; i < tmpsize; i++) { if(fabs(tmp[i] - tmp[i-1]) > 1e-6) bin[ ++size ] = tmp[i]; } }
int Binary(double v) { int l = 1; int r = size;
while(l <= r) { int m = (l + r) >> 1; if(fabs(v - bin[m]) < 1e-6) return m; if(v > bin[m]) l = m + 1; else r = m - 1; } }
void Build(int p, int l, int r) { T[p].l = l; T[p].r = r; T[p].p = p; T[p].nCover = 0; T[p].ylenOnce = T[p].ylenMore = 0;
if(l + 1 == r || l == r) { return ; } int mid = (l + r) >> 1; Build(p<<1, l, mid); Build(p<<1|1, mid, r); }
void Insert(int p, int l, int r, int val) {
if(r <= T[p].l || l >= T[p].r) return ;
if(l <= T[p].l && T[p].r <= r) { T[p].nCover += val; T[p].Update(); return ; }
Insert(p<<1, l, r, val); Insert(p<<1|1, l, r, val); T[p].Update(); } int n; int main() { int t; int i; scanf("%d", &t); while(t--) { tmpsize = 0; Vl.clear(); scanf("%d", &n); for(i = 0; i < n; i++) { double x0, x1, y0, y1; scanf("%lf %lf %lf %lf", &x0, &y0, &x1, &y1); Vl.push_back(VLine(x0, y0, y1, 1)); Vl.push_back(VLine(x1, y0, y1, -1)); tmp[ tmpsize++ ] = y0; tmp[ tmpsize++ ] = y1; }
sort(Vl.begin(), Vl.end(), cmp); Process(); Build(1, 1, size); double ans = 0; for(i = 0; i < Vl.size(); i++) { if(i) { ans += (Vl[i].x - Vl[i-1].x) * T[1].ylenMore; } int y1 = Binary(Vl[i].y1); int y2 = Binary(Vl[i].y2); if(y1 < y2) Insert(1, y1, y2, Vl[i].val); } printf("%.2lf\n", ans); } return 0; }
|