Atlantis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11332 Accepted Submission(s): 4817
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
2 10 10 20 20 15 15 25 25.5 0
Test case #1Total explored area: 180.00
以下为转载内容:http://www.cnblogs.com/fenshen371/p/3214092.html
顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。
![]()
如上图所示,坐标系内有两个矩形。位置分别由左下角和右上角顶点的坐标来给出。上下扫描法是对x轴建立线段树,矩形与y平行的两条边是没有用的,在这里直接去掉。如下图。
现想象有一条线从最下面的边开始依次向上扫描。线段树用来维护当前覆盖在x轴上的线段的总长度,初始时总长度为0。用ret来保存矩形面积总和,初始时为0。
由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。
用cover数组(通过线段树维护)来表示某x轴坐标区间内是否有边覆盖,初始时全部为0。插入或删除操作直接让cover[] += flag。当cover[] > 0 时,该区间一定有边覆盖。
开始扫描到第一条线,将它压入线段树,此时覆盖在x轴上的线段的总长度L为10。计算一下它与下一条将被扫描到的边的距离S(即两条线段的纵坐标之差,该例子里此时为3)。
则 ret += L * S. (例子里增量为10*3=30)
结果如下图
橙色区域表示已经计算出的面积。
扫描到第二条边,将它压入线段树,计算出此时覆盖在x轴上的边的总长度。
例子里此时L=15。与下一条将被扫描到的边的距离S=2。 ret += 30。 如下图所示。
绿色区域为第二次面积的增量。
接下来扫描到了下方矩形的顶边,从线段树中删除该矩形的底边,并计算接下来面积的增量。如下图。
蓝色区域为面积的增量。
此时矩形覆盖的总面积已经计算完成。 可以看到,当共有n条底边和顶边时,只需要从下往上扫描n-1条边即可计算出总面积。
<pre name="code" class="cpp">#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int maxm = 205; struct line { double x, y_down, y_up; int flag; }f[maxm * 4]; struct node { double x, y_down, y_up; int cover; bool flag; }tree[maxm * 1000]; double y[maxm * 3]; void make(int a, int b, int n); double query(int num, double x, double a, double b, int flag); bool cmp(line a, line b); int main() { int n, i, j, k, sum, id, cas=1; double x1, y1, x2, y2; while (scanf("%d", &n),n!=0) { id = 1; for (i = 1;i <= n;i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); y[id] = y1; f[id].x = x1; f[id].y_down = y1; f[id].y_up = y2; f[id++].flag = 1; y[id] = y2; f[id].x = x2; f[id].y_down = y1; f[id].y_up = y2; f[id++].flag = -1; } sort(y + 1, y + id); sort(f + 1, f + id, cmp); make(1, id-1, 1); double ans = 0; for (i = 1;i < id;i++) ans += query(1, f[i].x, f[i].y_down, f[i].y_up, f[i].flag); printf("Test case #%d\nTotal explored area: %.2f\n\n", cas++, ans); } } void make(int a, int b, int num) { tree[num].x = -1; tree[num].cover = 0; tree[num].y_down = y[a]; tree[num].y_up = y[b]; tree[num].flag = false; if (b - a == 1) { tree[num].flag = true; return; } int mid = (a + b) / 2; make(a, mid, num * 2); make(mid, b, num * 2 + 1); } double query(int num, double x, double a, double b, int flag) { if (b <= tree[num].y_down || a >= tree[num].y_up) return 0; if (tree[num].flag) { if (tree[num].cover) { double xx = tree[num].x; double ans = (x - xx)*(tree[num].y_up - tree[num].y_down); tree[num].x = x; tree[num].cover += flag; return ans; } else { tree[num].cover += flag; tree[num].x = x; return 0; } } double ans1, ans2; ans1 = query(num * 2, x, a, b, flag); ans2 = query(num * 2 + 1, x, a, b, flag); return ans1 + ans2; } bool cmp(line a, line b) { return a.x < b.x; }