线段树 - 面积交
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 - 面积交相关的知识,希望对你有一定的参考价值。
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
Output对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
Sample Input
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1Sample Output
7.63 0.00
思路 :
唯一区别于 矩形的面积并的地方 就是他所要的下边是被两次重复覆盖的边 。
代码示例 :
/* * Author: ry * Created Time: 2017/10/18 14:44:16 * File Name: 1.cpp */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <time.h> using namespace std; const int eps = 1e3+5; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; #define Max(a,b) a>b?a:b #define Min(a,b) a>b?b:a #define ll long long struct seg { double l, r, h; int pt; }po[eps]; struct node { int l, r, f; double len1, len2; }tree[eps<<2]; bool cmp(seg a, seg b){ return a.h < b.h; } double x[eps]; void build(int l, int r, int k){ tree[k].l = l, tree[k].r = r; tree[k].f = tree[k].len1 = tree[k].len2 = 0; if (l == r) return; int m = (l + r) >> 1; build(l, m, k<<1); build(m+1, r, k<<1|1); } void down(int k){ if (tree[k].f) tree[k].len1 = x[tree[k].r+1] - x[tree[k].l]; else if (tree[k].l == tree[k].r) tree[k].len1 = 0; else tree[k].len1 = tree[k<<1].len1 + tree[k<<1|1].len1; // 区别与矩形面积并的地方,tree[k].len2 表示被两次覆盖的线段的长度 if (tree[k].f >= 2) tree[k].len2 = tree[k].len1; else if (tree[k].f == 1) tree[k].len2 = tree[k<<1].len1 + tree[k<<1|1].len1; else if (tree[k].l == tree[k].r) tree[k].len2 = 0; else tree[k].len2 = tree[k<<1].len2 + tree[k<<1|1].len2; } void update(int l, int r, int k, int pt){ if (l <= tree[k].l && tree[k].r <= r){ tree[k].f += pt; down(k); return; } int m = (tree[k].l + tree[k].r) >> 1; if (l <= m) update(l, r, k<<1, pt); if (r > m) update(l, r, k<<1|1, pt); down(k); } int main() { int t, n; double a, b, c, d; cin >>t; while(t--){ cin >> n; int k = 1; for(int i = 1; i <= n; i++){ scanf("%lf%lf%lf%lf", &a, &b, &c, &d); po[k].l = po[k+1].l = a; po[k].r = po[k+1].r = c; po[k].h = b, po[k+1].h = d; po[k].pt = 1, po[k+1].pt = -1; x[k] = a, x[k+1] = c; k += 2; } sort(x+1, x+k); sort(po+1, po+k, cmp); int t = 2; for(int i = 2; i < k; i++){ if (x[i] != x[i-1]) x[t++] = x[i]; } build(1, t-1, 1); double ans = 0; for(int i = 1; i <= k; i++){ int l = lower_bound(x+1, x+t, po[i].l) - x; int r = lower_bound(x+1, x+t, po[i].r) - x - 1; update(l, r, 1, po[i].pt); ans += (po[i+1].h - po[i].h)*tree[1].len2; } printf("%.2f\n", ans); } return 0; }
以上是关于线段树 - 面积交的主要内容,如果未能解决你的问题,请参考以下文章
HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化