题意 : 在二维平面上给出 N 个矩形,问你所有矩形构成的图案的面积是多少(相互覆盖的地方只计算一次)

分析 : 

求矩形面积并可以模拟来做,不过使用线段树来辅助做扫描线可以更高效地求解

扫描线顾名思义就是类似有一条线在二维平面上扫过去,将矩形面积并给扫出来

实现是使用线段树来模拟这个扫描的过程

第一步就是确定扫描的方向,是从左到右扫还是从上到下扫,这里以从上到下为例

第二步就是确定题目的坐标是否可能很大,如果很大意味着线段树开不了,则要进行离散化操作

由于是从上到下,我们记录每个矩形的上下两条边的一些信息

此后将不再考虑矩形,而是从上到下考虑这些横线

此图引用了 ==>http://blog.csdn.net/u013480600/article/details/22548393

信息包括有矩形上下两条边的左右端点的横坐标值,以及两条线的纵坐标的值即高度

然后我们给两条边的上边和下边分别做个标记,标记的作用就是判断当前矩形是要计入还是删除

在扫到当前的边为上边的时候意味着要在线段树内进行区间加法,将这条线段的值累计到线段树中

在扫到当前的边为下边的时候意味着要在线段树内进行区间减肥,将这条线段的值从线段树中删去

此时线段树在从上到下扫的过程中就一直记录着有效的横坐标值,记得刚刚我们存储的横线的高度么?

只要将有效的横坐标值(线段之长)乘以上下两条边的高度之差便得到了当前两条线段之间的面积

#include<bits/stdc++.h>
#define LL long long
#define lson l, m, rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
;
const int Base = 1e8;
int add[maxn];
];
];
struct Node{
    int flag;
    int l, r, h;
    Node(){};
    Node(int L, int R, int H, int F):l(L),r(R),h(H),flag(F){};
    bool operator < (const Node & rhs) const{
        return this->h < rhs.h;
    };
}s[maxn];
inline void pushup(int rt, int l, int r)
{
    ] - x[l];/// 这里每一个 l 和 r 是离散化后的值
                                        /// 所以应当代入 x 数组来获取真实值
    ;
    ] + sum[rt<<|];
}

inline void update(int L, int R, int c, int l, int r, int rt)
{
    int m;
    if(L <= l && r <= R){
        add[rt] += c;
        pushup(rt, l, r);
        return ;
    }
    m = (l+r)>>;
    if(L <= m) update(L, R, c, lson);
    if(R >  m) update(L, R, c, rson);
    pushup(rt, l, r);
}

int main(void)
{
    int n;
    scanf("%d", &n);
    int x1, x2, y1, y2;
    ;
    ; i<n; i++){
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        x1 += Base, x2 += Base, y1 += Base, y2 += Base;/// 因为有负数坐标的存在,所以需要加上一个基数
        x[num] = x1;/// 记录所有出现的横坐标的值,方便离散化
        s[num++] = Node(x1, x2, y1, ); /// 将所有的横边(与x轴平行)以及其高度存储起来
        x[num] = x2;
        s[num++] = Node(x1, x2, y2, -);/// 顶边 flag == 1 而底边 flag == -1 是为了方便
                                        /// 从上到下扫描的时候做到,计入及删除这个矩形操作
    }
    sort(x, x+num);
    sort(s, s+num);
    int idx = std::unique(x, x+num) - x;/// 离散化横坐标
    int L, R;
    ;/// Attention !!!
    ; i<num-; i++){
        L = lower_bound(x, x+idx, s[i].l) - x;/// 找出线段树应当更新的左右界,注意是使用离散化后的值
        R = lower_bound(x, x+idx, s[i].r) - x - ;
        update(L,R,s[i].flag,,idx-,);/// 根据 flag 来确定是要删除还是添加操作
        ans+=(sum[]*(1LL*s[i+].h-1LL*s[i].h));/// 最后用当前存在的横坐标的总和去乘高度就是面积了,累加起来
    }
    printf("%lld\n", ans);
    ;
}

类似题目 : HDU 1542 Atlantis

#include<bits/stdc++.h>
#define LL long long
#define lson l, m, rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
;
int add[maxn];
], sum[maxn<<];
struct Node{
    int flag;
    double l, r, h;
    Node(){};
    Node(double L, double R, double H, int F):l(L),r(R),h(H),flag(F){};
    bool operator < (const Node & rhs) const{
        return this->h < rhs.h;
    };
}s[maxn];
inline void pushup(int rt, int l, int r)
{
    ] - x[l];
    ;
    ] + sum[rt<<|];
}

inline void update(int L, int R, int c, int l, int r, int rt)
{
    int m;
    if(L <= l && r <= R){
        add[rt] += c;
        pushup(rt, l, r);
        return ;
    }
    m = (l+r)>>;
    if(L <= m) update(L, R, c, lson);
    if(R >  m) update(L, R, c, rson);
    pushup(rt, l, r);
}

int main(void)
{
    , n;
    while(~scanf("%d", &n) && n){
        double x1, x2, y1, y2;
        ;
        ; i<n; i++){
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
            x[num] = x1;
            s[num++] = Node(x1, x2, y1, );
            x[num] = x2;
            s[num++] = Node(x1, x2, y2, -);
        }
        sort(x, x+num);
        sort(s, s+num);
        int idx = std::unique(x, x+num) - x;
        memset(add, , sizeof(add));
        memset(sum, , sizeof(sum));
        int L, R;
        ;
        ; i<num-; i++){
            L = lower_bound(x, x+idx, s[i].l) - x;
            R = lower_bound(x, x+idx, s[i].r) - x - ;
            update(L,R,s[i].flag,,idx-,);
            ans+=(sum[]*(s[i+].h-s[i].h));
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", Case++, ans);
    }
    ;
}

类似知识点 : 利用扫描线求矩形周长并

USACO Overplanting ( 线段树扫描线 )的更多相关文章

  1. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  2. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  3. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  4. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  5. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  6. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  7. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

  8. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

  9. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

随机推荐

  1. LeetCode.867-转置矩阵(Transpose Matrix)

    这是悦乐书的第332次更新,第356篇原创 01看题和准备 今天介绍的是LeetCode算法题中Easy级别的第202题(顺位题号是867).给定矩阵A,返回A的转置. 矩阵的转置是在其主对角线上翻转 ...

  2. javascript 异常处理

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  3. Java Mail 附件名太长导致接收端附件名解析出错

    问题前提:公司需要往邮件中写 excle 文件,返送成功后发现文件格式有误(如:xxxx.bat 等文件后缀),但是有些文件又不会, 后来发现是由于文件名称太长所导致. 问题原因:java mail中 ...

  4. Zend_Cache的使用

    一.Zend_Cache快速浏览 Zend_Cache 提供了一个缓存任何数据的一般方法. 在Zend Framework中缓存由前端操作,同时通过后端适配器(File, Sqlite, Memcac ...

  5. Linux cd命令(4)

    可以说在Linux上的一切操作都是从 cd 命令开始的.cd 是change directory的简写,其作用就是更改当前工作目录. 使用cd 对于这个命令的使用,不用多说了.需要注意的两点就是: c ...

  6. Ubuntu 解决wifi无法打开的问题 安装NVIDIA显卡驱动的正确姿势

    游戏本型号Y7000 win10 Ubuntu16.04双系统 解决wifi无法打开的问题 解决方法: 1.打开终端输入:rfkill list all 出现如下提示::       可以看到,优先级 ...

  7. 关于css清除浮动

    1.overflow:hidden 较简单,兼容于市面浏览器.负面效果不详.暂不推荐使用.2.定义clear类,并把clear类赋给浮动元素的父级元素. .clear{display:block;ov ...

  8. Vue-Quill-Editor 富文本编辑器

    通俗来说:富文本,就是比较丰富的文本编辑器.普通的框只能输入文字,而富文本还能给文字加颜色样式等. 富文本编辑器有很多,例如:KindEditor.Ueditor.但并不原生支持vue 但是我们今天要 ...

  9. SPSS Statistics 26.0 下载安装和激活

    目录 1. 其他版本 2. IBM SPSS Statistics 26 新增功能 3. 安装步骤 4. 下载地址 1. 其他版本 参考:https://www.cnblogs.com/coco56/ ...

  10. Nginx 详细介绍

    Nginx 和 Apache 一样是 http 服务器软件.它们的区别是 Apache 的处理速度慢,占用内存资源, nginx 恰恰相反.在功能上 Apache 的所有模块都支持动和静态编译,而 n ...