POJ1389:Area of Simple Polygons——扫描线线段树题解+全套代码注释
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——扫描线线段树题解+全套代码注释的更多相关文章
- POJ 1389 Area of Simple Polygons 扫描线+线段树面积并
---恢复内容开始--- LINK 题意:同POJ1151 思路: /** @Date : 2017-07-19 13:24:45 * @FileName: POJ 1389 线段树+扫描线+面积并 ...
- 【POJ 1389】Area of Simple Polygons(线段树+扫描线,矩形并面积)
离散化后,[1,10]=[1,3]+[6,10]就丢了[4,5]这一段了. 因为更新[3,6]时,它只更新到[3,3],[6,6]. 要么在相差大于1的两点间加入一个值,要么就让左右端点为l,r的线段 ...
- POJ1389 Area of Simple Polygons 线段树
POJ1389 给定n个整数点矩形,求面积并. 显然ans必然是整数. 记录若干个事件,每个矩形的左边的竖边记为开始,右边的竖边记为结束. 进行坐标离散化后用线段树维护每个竖的区间, 就可以快速积分了 ...
- POJ Area of Simple Polygons 扫描线
这个题lba等神犇说可以不用离散化,但是我就是要用. 题干: Description There are N, <= N <= , rectangles -D xy-plane. The ...
- POJ 1389 Area of Simple Polygons | 扫描线
请戳此处 #include<cstdio> #include<algorithm> #include<cstring> #define N 1010 #define ...
- hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积
题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...
- HDU 3642 - Get The Treasury - [加强版扫描线+线段树]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...
- 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 ...
- 【BZOJ4999】This Problem Is Too Simple!(线段树)
[BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...
随机推荐
- 开胃小菜——impress.js代码详解
README 友情提醒,下面有大量代码,由于网页上代码显示都是同一个颜色,所以推荐大家复制到自己的代码编辑器中看. 今天闲来无事,研究了一番impress.js的源码.由于之前研究过jQuery,看i ...
- 编译chromium时下载gn.exe时出错的解决方案
天朝人写个代码真难,想要编译一下chromium,但是获取代码时各种坑,不是网速慢,就是网络联不通,真难玩. 本文针对下载gn.exe等工具时失败的解决方案. 原因1:gclient没有走代理,针对使 ...
- Qt-第一个QML程序-2-关键代码分析,TEXT,Image,Mouseare
qml语言开始写的时候有点不习惯,后面用的多了感觉很好,很顺手,用于快速搭建项目界面,真的很好. 目前用到的还是比较简单的 隐藏标题栏,而依附任务栏 flags: Qt.Window | Qt.Fra ...
- mysql优化理解笔记(持续更新)
主要包括存储引擎.索引.sql语句 一.存储引擎 目前最常见的是InnoDB和MyISAM两个存储引擎 (1)InnoDB:支持事务处理,提供行级锁.外键约束索引,行锁 (2)MyISAM:支持全文搜 ...
- 第三模块:面向对象&网络编程基础 第2章 网络编程
01-计算机基础 02-什么是网络 03-五层协议详解 04-传输层详解 05-什么是Socket 06-基于socket实现简单套接字通信 07-在简单套接字基础上加上通信循环 08-客户端与服务端 ...
- 【hidden】微信小程序hidden属性使用示例
hidden属性用于隐藏标签,代码示例: <view hidden="{{!statusTag}}">我出来了~</view> <button bin ...
- 从零开始的Python学习Episode 2——运算符与while循环
一.算术运算符 加法:+,减法:-,乘法*,除法/,整除(地板除)//,取余%,乘方**. 二.逻辑运算符 且:and,或:or,非:not 优先级:not>and>or 短路原则: 对 ...
- 剑指offer-栈的压入弹出序列21
题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压 ...
- 第一章 Windows编程基础(1~4课)
第一课:从main到WinMain 第二课:窗口和消息 第三课:MFC编程 第四课:MFC应用程序框架 概括: Win32的两种编程框架:SDK方式.MFC方式 1. SDK方式:使用WinMain入 ...
- php中array_map和array_walk的使用对比
一.array_map() 1.array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组,若函数作用后无返回值,则对应的新值数组中为空. 2.回调 ...