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. 文件同步 单向rsync 双向unison 监控inotifywait 免密登录

    1.负载均衡中文件同步必不可少,我这边选择rsync来实现文件同步 rsync同步文件机制更适用于单向文件同步,可配合unison实现双向同步功能. 实现同步的两种方法 一:ssh方法 rsync - ...

  2. FastJson - 从HttpEntity到Json

    在使用java + httpClient施行API自动化时,不可避免地遇到了如下问题: 1. 用Http Response数据做断言: 2. 用上一个请求的Response内容,作为下一个请求的参数: ...

  3. python操作字符串内容并重新输出

    今天在做一个函数的作业,题目如下: 编写一个函数实现大写转小写,小写变大写,并且转换为镜像字符串,并且将字符串变为镜像字符串. 例如:’A’变为’Z’,’b’变为’y 示范字符串: ”sdSdsfdA ...

  4. fizzbuzz Python很有意思的解法

    写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz” 题目不难,解起来容易,用for循环做if,e ...

  5. HDU - 6438(贪心+思维)

    链接:HDU - 6438 题意:给出 n ,表示 n 天.给出 n 个数,a[i] 表示第 i 天,物品的价格是多少.每天可以选择买一个物品,或者卖一个已有物品,也可以什么都不做,问最后最大能赚多少 ...

  6. vim基本命令笔记

    两种模式 -编辑模式:可以进行正常的编辑操作 左下方显示 -- INSERT -- "在命令模式下输入 i 能够进入编辑模式" -命令模式:可以通过命令 左下方什么也不显示 &qu ...

  7. docker学习2

    今天继续学习docker! 搜索镜像 docker search centos 下载镜像 docker pull name(镜像名字) 查看镜像docker images 字段含义分析: TAG:仓库 ...

  8. AttributeError: 'TimeLimit' object has no attribute 'monitor'

    原报错代码部分: env.monitor.start(monitor_path, resume=True, video_callable=lambda count: count % record_vi ...

  9. 域名加www与不加www不一样结果的解决办法

    有些浏览器域名访问加www 与不加www出现的页面不一样.在aj请求的时候也不同.firefox与google新版本的都会自动加上www. 比如 访问haitaohua.com,但aj请求的时候是带w ...

  10. unity 学习记录

    世界第九条约定 缘起 嗯,其实一开始我知道unity是个弄游戏的,也知道好像神庙逃亡,炉石都是出自unity,然后舍友都报了,我也觉得这个东西挺高大上的,所以忍不住自己的双手,报了名,确实,这能学到很 ...