线段树 - 面积交

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 1
Sample 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 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化

计算直角坐标系的面积并和面积交(可小数)

poj-1151矩形面积并-线段树

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

hdu 1542 线段树之扫描线之面积并