http://poj.org/problem?id=1389

题面描述
在二维xy平面中有N,1 <= N <= 1,000个矩形。矩形的四边是水平或垂直线段。矩形由左下角和右上角的点定义。每个角点都是一对两个非负整数,范围从0到50,000,表示其x和y坐标。

求出所有矩形的面积(重叠部分只算一次)

示例:考虑以下三个矩形:

矩形1:<(0,0)(4,4)>,

矩形2:<(1,1)(5,2)>,

矩形3:<(1,1)(2,5)>。

所有由这些矩形构造的简单多边形的总面积为18。

输入
输入由多个测试用例组成。一行4 -1分隔每个测试用例。一个额外的4 -1的行标志着输入的结束。在每个测试用例中,矩形都是一行一个地排列的。在矩形的每一行中,给出4个非负整数。前两个是左下角的x和y坐标。接下来的两个是右上角的x和y坐标。

输出
对于每个测试用例,输出所有简单多边形的总面积。

示例输入
0 0 4 4
1 1 5 2
1 1 2 5
-1 -1 -1 -1
0 0 2 2
1 1 3 3
2 2 4 4
-1 -1 -1 -1
-1 -1 -1 -1

示例输出
18
10

线段树的妙用之一——扫描线。

我们先将坐标离散化(然而这题数据小,不需要)

然后将一个矩形分成两半,存下它的下边界和上边界,并且用w记录哪个是上边界哪个是下边界。

这里先将上边界w=-1,下边界w=1(下面说为什么)

然后我们按照每个边界的y从小到大排序(如果y相同,先添加上界)。

这样预处理就完成了。

完后开始想线段树的含义。

节点表示其区间内被覆盖的点(不算重复)的数目。

那么我们假设一条边的长度为k,那么其覆盖的点的数量就是看k+1,于是为了方便起见,我们把边界都少存一位,这样我们就可以用这个表示边界长度了。

然后我们一条一条添加边,等效于在线段树区间内+w。

现在你知道为什么上边界w=-1了:标志着这个矩形结束了,就是把原来被覆盖的点撤回。

那么显然从上一个边界到下一个边界中矩形覆盖的面积就是tree[1]*上下边界距离。

把他们都加在一起就是答案,这样做是不是很巧妙的避免了重复面积啊(原因是被覆盖的点没有被重复计算)!

但是这样问题就变成了如何求被覆盖的点(不算重复)的数目了。

我们用lazy标记表示当前区间被一整条下边界完全经过,这样的边的边数。

如果lazy>0说明该区间被完全覆盖了。

如果lazy=0:

如果此时l=r,直接更新为0(显然)。

如果不是,我们就需要重新更新节点的值了,那就是他的左右儿子的节点个数和。

(思考lazy=0只是说明了该区间没有被完全覆盖,但是它可能被非完全经过的下边界覆盖了)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
inline int read(){
int X=,w=; char ch=;
while(ch<'' || ch>'') {if(ch=='-') w=-;ch=getchar();}
while(ch>='' && ch<='') X=(X<<)+(X<<)+ch-'',ch=getchar();
return X*w;
}
struct node{
int y;
int x1;
int x2;
int w;
}edge[];
bool cmp(node a,node b){
return a.y<b.y;
}
int tree[];//区间被覆盖点数
int lazy[];//当前区间被一整条下边界完全经过,这样的边的边数
void build(int a,int l,int r){
lazy[a]=;
if(l==r){
tree[a]=;
return;
}
int mid=(l+r)>>;
build(a*,l,mid);
build(a*+,mid+,r);
tree[a]=tree[a*]+tree[a*+];
return;
}
void add(int a,int l,int r,int l1,int r1,int w){
if(r1<l||l1>r)return;
if(l1<=l&&r<=r1){
lazy[a]+=w;
if(lazy[a]>)tree[a]=r-l+;//完全覆盖,值为区间长
else if(l==r)tree[a]=;//该点没有被覆盖,清零
else tree[a]=tree[a*]+tree[a*+];//没有被完全覆盖,需要重新更新
return;
}
int mid=(l+r)>>;
add(a*,l,mid,l1,r1,w);
add(a*+,mid+,r,l1,r1,w);
if(lazy[a]==)tree[a]=tree[a*]+tree[a*+];//没有被完全覆盖,需要重新更新
return;
}
int main(){
bool ok=;
while(){
int n=;
while(){
int a=read();
int b=read();
int c=read();
int d=read();
if(a==b&b==c&&c==d&&a==-){
if(!n)ok=;
break;
}
n++;
edge[n*-].x1=a;
edge[n*-].y=b;
edge[n*-].x2=c;
edge[n*].y=d;
edge[n*-].w=;//到下界时加上该矩形
edge[n*].w=-;//到上界时去掉该矩形
edge[n*].x1=edge[n*-].x1;
edge[n*].x2=edge[n*-].x2;
}
if(ok==)break;
sort(edge+,edge+*n+,cmp);
//根据上下界大小排序,从下往上扫描矩形
build(,,);
ll h,ans=;
add(,,,edge[].x1+,edge[].x2,edge[].w);
//建一个底
//因为是点数和,所有求长度的话要减去一个点就为长度
for(int i=;i<=*n;i++){
h=edge[i].y-edge[i-].y;//下一个矩形的下界(或者刚才的矩形的上界)之差即为高
ans+=h*tree[];//底乘高为面积
add(,,,edge[i].x1+,edge[i].x2,edge[i].w);//加上新矩形(或减去旧矩形)
}
printf("%lld\n",ans);
}
return ;
}

POJ1389:Area of Simple Polygons——扫描线线段树题解+全套代码注释的更多相关文章

  1. POJ 1389 Area of Simple Polygons 扫描线+线段树面积并

    ---恢复内容开始--- LINK 题意:同POJ1151 思路: /** @Date : 2017-07-19 13:24:45 * @FileName: POJ 1389 线段树+扫描线+面积并 ...

  2. 【POJ 1389】Area of Simple Polygons(线段树+扫描线,矩形并面积)

    离散化后,[1,10]=[1,3]+[6,10]就丢了[4,5]这一段了. 因为更新[3,6]时,它只更新到[3,3],[6,6]. 要么在相差大于1的两点间加入一个值,要么就让左右端点为l,r的线段 ...

  3. POJ1389 Area of Simple Polygons 线段树

    POJ1389 给定n个整数点矩形,求面积并. 显然ans必然是整数. 记录若干个事件,每个矩形的左边的竖边记为开始,右边的竖边记为结束. 进行坐标离散化后用线段树维护每个竖的区间, 就可以快速积分了 ...

  4. POJ Area of Simple Polygons 扫描线

    这个题lba等神犇说可以不用离散化,但是我就是要用. 题干: Description There are N, <= N <= , rectangles -D xy-plane. The ...

  5. POJ 1389 Area of Simple Polygons | 扫描线

    请戳此处 #include<cstdio> #include<algorithm> #include<cstring> #define N 1010 #define ...

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

    题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...

  7. HDU 3642 - Get The Treasury - [加强版扫描线+线段树]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  8. HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  9. 【BZOJ4999】This Problem Is Too Simple!(线段树)

    [BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...

随机推荐

  1. nginx下pagespeed使用详解

    目录 1.简介 2.安装 2.1脚本安装 查看该脚本的如何使用 使用脚本自动安装 替换以前的nginx 2.2 手动安装 先安装基本依赖 构建pagespeed 重新编译安装nginx 3.配置 3. ...

  2. Docker - vim安装

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim. apt-get install vim 若提示: R ...

  3. hive读书笔记

    笔记来源<Hive编程指南> 一.hive命令行界面: ‘一次使用’命令:执行一个或多个(分号分隔)查询后hive CLI立即退出: hive -e "select * from ...

  4. WPF Issues

    Grid row height is star, but the height setting does not work in a prism:region Problem: My original ...

  5. uvaoj 489 - Hangman Judge(逻辑+写代码能力)

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  6. Windows运行机理——主程序—WinMain

    Windows运行机理这系列文章都是来至于<零基础学Qt4编程>——吴迪,个人觉得写得很好,所以进行了搬运和个人加工 在windows 操作系统下,用C 或者C++来编写MS-DOS 应用 ...

  7. Appium的环境搭建和配置

    Appium的环境搭建和配置 一.安装Nodejs 下载nodejs安装包(https://nodejs.org/en/download/)安装 下载后,双击安装文件,按提示来安装. 测试安装是否成功 ...

  8. 用libevent实现的echo服务器及telnet客户端

    以下代码在vs 2010编译通过,使用的libevent版本是:libevent-2.0.22,win7环境测试通过. 服务器实现: 1 流程图: 2 代码: // my_telnet.cpp : D ...

  9. [Clr via C#读书笔记]Cp1CLR执行模型

    Cp1CLR执行模型 本章的概念点 CLR=Common Language Runtime 内存管理,程序集加载,安全性,异常处理和线程同步.CLR是基础,支持着面向它的各种语言.各种语言会被对应的编 ...

  10. 七:Web Application Proxy

    yarn自带了web接口,默认是和RM一起的(8088端口).但是为了减少从web接口受到的攻击,可以把Web接口单独放在别的机器上. 设置下web代理就行了 Configurations Confi ...