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. dsp5509的中断系统

    1. DSP5509有32个中断,中断分为软件中断和硬件中断,同时软件中断不可以屏蔽.软件中断由指令触发.55x在中断时DSP会自动保存ST0_55.ST1_55.ST2_55三个寄存器. 2. 其中 ...

  2. gdb 分析出错

    1 创建测试代码test.php <?php function test1(){ while(true){ sleep(1); } }echo getmypid() "\r\n&quo ...

  3. 基于Spring的最简单的定时任务实现与配置(二)

    接上一篇,原本我以为我实现的方式很简单了,在准备写(一)的时候,就去查了查别人是怎么实现定时任务的.不查还好,这一查,发现还有更简单的.所以就会有这篇文章. 本文主要是讨论,在完成Spring 项目搭 ...

  4. 微信小程序—day05

    小程序云服务器--环境配置 本来想要买腾讯云的云服务器,作为小程序的服务端的.无奈,腾讯云卖的太贵了,比阿里云要贵一倍,想想还是算了. 但是,没有服务端的接受,小程序的一些功能是实现不了的.找了一圈, ...

  5. SQL 从入门到 DBA 删库跑路

    SQL 从入门到 DBA 删库跑路 一.基础 人员信息表: ID 姓名 性别 出生 婚否 学历 工资 工会 35009449 孙xx 男 1978-2-17 未婚 中专 3000 TRUE 35000 ...

  6. Python 关键字参数和可变参数

    关键字参数 如果你有一些具有许多参数的函数,而你又希望只对其中的一些进行指定,那么你可以通过命名它们来给这些参数赋值——这就是python关键字参数(Keyword Arguments)——我们使用命 ...

  7. 树的层次遍历(Trees on the level,UVA 122)

    题目描述: 题目思路: 1.用结构链表来建树 2.用队列来实现层次遍历,当遍历到根节点时,将其子节点压入队列 #include <iostream> #include <cstdli ...

  8. 孤荷凌寒自学python第八十二天学习爬取图片2

    孤荷凌寒自学python第八十二天学习爬取图片2 (完整学习过程屏幕记录视频地址在文末) 今天在昨天基本尝试成功的基础上,继续完善了文字和图片的同时爬取并存放在word文档中. 一.我准备爬取一个有文 ...

  9. Skype for Business Server 方案

    方案说明: 高可用性的配置屏蔽了单点故障,使得当一个服务器节点失效时,另外的可用的节点能够进行服务的接管.可伸缩性的配置可以保证当即时沟通平台的使用用户增加时,该平台应该具有良好的可伸缩性,能非常方便 ...

  10. react和vue的区别

    1.数据改变的方式 react是通过setState来改变数据,然后重走组件的渲染过程.而vue是通过Object.defineProperty和watcher来显示响应式的数据,所以数据的改变是直接 ...