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. 深入解析UUID及其应用(转载)

    UUID 编辑 UUID含义是通用唯一识别码 (Universally Unique Identifier),这 是一个软件建构的标准,也是被开源软件基金会 (Open Software Founda ...

  2. Use GitHub Desktop to get GitHub projects

    Find the project's https git file in the home page of the project. e.g. https://github.com/PrismLibr ...

  3. Qt 独立运行时伴随CMD命令窗口

    用Qt写了一个小软件,在把程序release后,打包分装后,发现程序运行的时候会伴随cmd命令窗口,可把我愁怀了 不过功夫不负有心人,在老师和我网友的帮助下,终于搞完了 CONFIG:指定工程配置和编 ...

  4. Pycharm中查看方法的源码

    方法1.鼠标放在函数上,Ctrl+B,看源码 方法2.将光标移动至要查看的方法处,按住ctrl 键,点击鼠标左键,即可查看该方法的源码.

  5. Vue动画效果

    1.哪些元素/那些组件适合在那些条件下实现动画效果 条件渲染 (使用 v-if) 条件展示 (使用 v-show) 动态组件 组件根节点 简单经典例子:(文字隐藏到显示效果) <div> ...

  6. (python)leetcode刷题笔记 01 TWO SUM

    1. Two Sum Given an array of integers, return indices of the two numbers such that they add up to a ...

  7. Ubuntu—安装网络调试工具

    https://pan.baidu.com/s/1G6oHXp3SvcN6HMAMqTdqhA 1,在ubuntu的终端下,切换到网络调试工具所在的目录 $ cd 桌面/    #我的放在桌面上 2, ...

  8. [C++] in-class initializer

    C++11 introduced serveral contructor-related enhancements including: Class member initializers Deleg ...

  9. C语言文件进阶操作

    Description文件a.dic.b.dic.c.dic中分别存有张三的三科成绩,每个文件都是16字节:前8个字节存储其英文名字zhangsan,后面是一个空格,其后的2个字节存储其年龄(文本方式 ...

  10. 2017秋软工1 - 本周PSP

    1.本周PSP 2. 本周PSP饼状图 3. 本周进度条 4. 累计进度图