zoukankan      html  css  js  c++  java
  • 线段树

    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.



    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/24 8:57:44
     * 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 = 3e+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 f;
    }po[eps];
    double x[eps];
    
    bool cmp(seg a, seg b){
        return a.h < b.h;
    }
    
    struct node
    {
        int l, r, sum;
        double len1, len2;
    }pre[eps<<2];
    
    void build(int l, int r, int k){
        pre[k].l = l;
        pre[k].r = r;
        pre[k].sum = pre[k].len1 = pre[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 (pre[k].sum) pre[k].len1 = x[pre[k].r+1] - x[pre[k].l]; 
        else if (pre[k].l == pre[k].r) pre[k].len1 = 0;
        else pre[k].len1 = pre[k<<1].len1 + pre[k<<1|1].len1;
        
        // 区别于矩形面积并得地方,多有一个检测是否有被覆盖两次的边 
        // 要注意这几个 if else 的顺序 ,顺序不一样就会错哦 , 可以想想为什么
        if (pre[k].sum >= 2) pre[k].len2 = pre[k].len1;
        else if (pre[k].l == pre[k].r) pre[k].len2 = 0; 
        else if (pre[k].sum == 1) pre[k].len2 = pre[k<<1].len1 + pre[k<<1|1].len1;
        else pre[k].len2 = pre[k<<1].len2 + pre[k<<1|1].len2;
    }
    
    void update(int l, int r, int k, int pt){
        if (l <= pre[k].l && pre[k].r <= r){
            pre[k].sum += pt;
            down(k);
            return;
        }
        int m = (pre[k].l + pre[k].r) >> 1;
        // 这个地方当时写完有一个BUG ,一顿找啊 我是,就是自己写线段树,习惯了 l , m , k<<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 = 0; 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].f = 1, po[k+1].f = -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].f);
                ans += pre[1].len2*(po[i+1].h - po[i].h);
            }
            printf("%.2f
    ", ans);
        }
    
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    应用图标大小
    AndroidStudio使用笔记
    shell 三剑客之 sed 命令详解
    shell 三剑客之 sed pattern 详解
    shell 文本处理三剑客之 grep 和 egrep
    Shell 编程中的常用工具
    shell 函数的高级用法
    shell 数学运算
    shell 变量的高级用法
    nginx 之 https 证书配置
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/7689902.html
Copyright © 2011-2022 走看看