平面上有若干个矩形,求矩形相互覆盖的面积。为方便起见,矩形的边均平行于坐标轴。

我们根据容斥原理矩形相互覆盖的面积即为所有矩形的面积和减去所有矩形所覆盖的面积即可。

而现在问题是如何求得所有矩形所覆盖的面积。即

让我们人类去做,由于这是个由矩形拼接成的多边形,很难去直接求它的面积,求该图形的面积一个常规的方法就是割补法

此处我们采用割,割成一个一个矩形出来。

这样就很方便地去求了。

计算机无法直观地看出图形,进而去求出长宽进而求出矩形面积。

那该如何让计算机来求?

我们看这些图形,一块一块的,最下面的一块,可以想象成原矩形

下面矩形最下面的边,向上平移时“”出来的紫矩形,当碰到上面矩形的底边时,两条边合并,再向上平移时“”出红色矩形,然后碰到下面矩形的顶边,去掉了顶边对应的底边,因为两边重合的部分有两条边贡献,所以去掉顶边线段后,重合部分还在,继续向上平移,“”出了蓝色矩形。

有序,易行,计算机可做!

其实这就是扫描线在干的事,一条透明的线从下向上平移,遇到底边,则扫描线在底边所在的范围有了颜色,这样向上平移的时候就“”出了颜色,遇到顶边,则扫描线在顶边的范围就没了颜色,之后该部分就没有颜色了。

所以现在的问题是,如何维护扫描线

即我们要维护,扫描线有底边贡献的范围,以及该范围被几条底边所贡献,且当遇到顶边时要把相应底边的贡献去掉

很显然,当底边两端点的坐标为实数,或者坐标范围很大时,直接维护点坐标是不现实的。

实数怎么办?范围很大怎么办?

离散呀!

我们注意到,所有矩形顶点的横坐标,其实是把x轴分成了若干个区间。

而任意一个矩形的底边,只是会覆盖若干个区间,而不会只覆盖某区间的一部分。

那我们就可以维护区间,从而避开了实数的无穷个数和范围大造成数据冗余以及内存爆表的问题。

当我们遇到一个矩形的底边时,只需在底边所覆盖的若干个区间加一,即贡献一个底边。

而在遇到一个矩形的顶边的时候,在顶边所覆盖的若干个区间减一,即去除该矩形底边的贡献。

最终,只要有底边有贡献的区间,都是扫描线“有颜色”的范围。

这里涉及到了区间加,区间减以及区间查询。

拿什么维护呢。

当然是线段树啦。

所以,

根据边的x坐标划分离散x轴的区间,

拿线段树去维护区间,

把边按y轴从小到大排序,自1到n即自下而上扫描,

不断更新扫描线的有颜色的范围长度,再乘以上下两边的y轴的数值差,即为此部分扫描的面积。

重复即可。

离散的写法有好多,这里运用STLl较为简便的写法。

注意离散后也要能映射回去。

POJ1151

Description

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input

The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area. 
The input file is terminated by a line containing a single 0. Don't process it.

Output

For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point. 
Output a blank line after each test case.
 
大意就是求岛的面积(还是矩形的),给出若干个矩形,以左上和右下点的坐标来表示,矩形间会有重叠,重叠部分只算一次。
扫一下就好了。
注意原题的一句话
Output a blank line after each test case.
否则你会Presentation Error
 
 #include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <ctime>
#include <queue>
#define N 200
using namespace std;
struct seg{ //边
double l,r,h;
int d;
seg(){}
seg(double xx,double yy,double hh,int dd):l(xx),r(yy),h(hh),d(dd){} //初始化函数
bool operator < (const seg &a) const{ //重载运算符,使其能够进行快排
return (h<a.h);
}
}s[N*];
struct tree{ //线段树
int mark; //mark记录底边对区间的贡献
double sum; //sum记录底边贡献的范围
}t[N*];
int n,ll,rr,num,size,qwq; //qwq
double ans,rank[N*]; //rank做离散用
void readint(int &x){
x=;
char c;
int w=;
for (c=getchar();c<''||c>'';c=getchar())
if (c=='-') w=-;
for (;c>=''&&c<='';c=getchar())
x=(x<<)+(x<<)+(c^'');
x*=w;
}
void readlong(long long &x){
x=;
char c;
long long w=;
for (c=getchar();c<''||c>'';c=getchar())
if (c=='-') w=-;
for (;c>=''&&c<='';c=getchar())
x=(x<<)+(x<<)+(c^'');
x*=w;
}
void pushup(int root,int ll,int rr){
if (t[root].mark) t[root].sum=rank[rr+]-rank[ll]; //离散后的数字映射回原来的数字
else if (ll==rr) t[root].sum=;
else t[root].sum=t[root<<].sum+t[root<<|].sum;
}
void updata(int l,int r,int d,int root,int ll,int rr){
if (l<=ll&&rr<=r){
t[root].mark+=d;
pushup(root,ll,rr);
return;
}
int mid=(ll+rr)>>;
if (l<=mid) updata(l,r,d,root<<,ll,mid);
if (r>mid) updata(l,r,d,root<<|,mid+,rr);
pushup(root,ll,rr);
}
int main(){
qwq=;
while (true){
++qwq; //qwq只是情况记录的个数qwq
num=;
ans=;
readint(n);
if (n==) return ; //应题目要求
for (int i=;i<=n;++i){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
s[++num]=seg(x1,x2,y2,);
rank[num]=x1;
s[++num]=seg(x1,x2,y1,-);
rank[num]=x2;
}
sort(rank+,rank++num);
sort(s+,s++num);
size=unique(rank+,rank++num)-(rank+); //去重,size为去重后点的个数,为离散做准备
s[num+].h=s[num].h; //小细节,只为下面i循环后mark能清零且不会在i=n时对结果造成影响
for (int i=;i<=num;++i){
ll=lower_bound(rank+,rank++size,s[i].l)-(rank+)+; //这里左边第一个点标号为1,其点右边第一个区间标号也为1
rr=lower_bound(rank+,rank++size,s[i].r)-(rank+); //离散,ll,rr为边覆盖的最左区间和最右区间的标号
updata(ll,rr,s[i].d,,,size-); //植树原理,一条直线,两头植树,n个点,n-1个区间
ans+=t[].sum*(s[i+].h-s[i].h); //长乘宽
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",qwq,ans);
}
return ;
}

神奇的代码

什么?你说4+2第一天那道绝地求生,有若干个圆形辐射区,问安全区的面积怎么用扫描线扫?

那听说是道圆的面积并的模板题,但本蒟蒻还不会……

扫描线——POJ1151的更多相关文章

  1. 【POJ1151】Atlantis(线段树,扫描线)

    [POJ1151]Atlantis(线段树,扫描线) 题面 Vjudge 题解 学一学扫描线 其实很简单啦 这道题目要求的就是若干矩形的面积和 把扫描线平行于某个轴扫过去(我选的平行\(y\)轴扫) ...

  2. Atlantis poj1151 线段树扫描线

    Atlantis poj1151 线段树扫描线 题意 题目给了n个矩形,每个矩形给了左下角和右上角的坐标,矩形可能会重叠,求的是矩形最后的面积. 题解思路 这个是我线段树扫描线的第一题,听了学长的讲解 ...

  3. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

  4. 【POJ1151】【扫描线+线段树】Atlantis

    Description There are several ancient Greek texts that contain descriptions of the fabled island Atl ...

  5. poj1151 Atlantis (线段树+扫描线+离散化)

    有点难,扫描线易懂,离散化然后线段树处理有点不太好理解. 因为这里是一个区间,所有在线段树中更新时,必须是一个长度大于1的区间才是有效的,比如[l,l]这是一根线段,而不是区间了. AC代码 #inc ...

  6. Atlantis(POJ1151+线段树+扫描线)

    题目链接:http://poj.org/problem?id=1151 题目: 题意:求所有矩形的面积,重合部分只算一次. 思路:扫描线入门题,推荐几篇学扫描线的博客: 1.http://www.cn ...

  7. Poj1151&HDU1542 Atlantis(扫描线+线段树)

    题意 给定\(n​\)个矩形\((x_1,y_1,x_2,y_2)​\),求这\(n​\)个矩形的面积并 题解 扫描线裸题,可以不用线段树维护,\(O(n^2)\)是允许的. #include < ...

  8. POJ1151 Atlantis 线段树扫描线

    扫描线终于看懂了...咕咕了快三个月$qwq$ 对于所有的横线按纵坐标排序,矩阵靠下的线权值设为$1$,靠上的线权值设为$-1$,然后执行线段树区间加减,每次的贡献就是有效宽度乘上两次计算时的纵坐标之 ...

  9. ACM学习历程—POJ1151 Atlantis(扫描线 && 线段树)

    Description There are several ancient Greek texts that contain descriptions of the fabled island Atl ...

随机推荐

  1. win10 uwp 异步转同步

    原文:win10 uwp 异步转同步 有很多方法都是异步,那么如何从异步转到同步? 可以使用的方法需要获得是否有返回值,返回值是否需要. 如果需要返回值,使用GetResults 如从文件夹获取文件: ...

  2. Win10《芒果TV - Preview》官方指定预览版 - 重要使用注意事项

    Win10<芒果TV - Preview>官方指定预览版,最新的改进和功能更新将会此版本优先体验. 重要使用注意事项: 1.因为方便过审核,默认将会员相关的操作提示简化: 2.使用中务必手 ...

  3. DIXML(包括所有的W3C XML标准)

    Description:DIXml is an embedded XML, XSLT, and EXSLT processing library for Delphi (Embarcadero / C ...

  4. ASP.NET Core 通过 Microsoft.DotNet.Watcher.Tools 实现热部署

    之前开发前端的时候,webpack 会有热更新工具,在修改了代码之后,自动将代码编译,实时展现到页面上,给开发带来了极大的方便. Java也可以通过第三方插件JRebel实现热部署,不用频繁的重启To ...

  5. 3021Java_数据类型

    1.分类 Java数据类型 基本数据类型 数值型 整数类型 浮点类型 字符型 布尔型 引用数据类型 类 接口 数组 2.基本数据类型 2.1 综述 java的8种基本数据类型(简单数据类型) bool ...

  6. .NET中生成水印更好的方法

    .NET中生成水印更好的方法 为了保护知识产权,防止资源被盗用,水印在博客.网店等场景中非常常见. 本文首先演示了基于System.Drawing.Image做正常操作.然后基于Direct2D/WI ...

  7. 不一样的go语言-玩转语法之二

      本文继续玩转语法,是为之二.   I/O(Input/Output),输入输出是计算机最为突出的特点,也可以说是计算机最为核心的功能.没有I/O,计算机就是一堆废铜废铁.从最低层的电子元器件开始, ...

  8. Electron构建一个文件浏览器应用(二)

    在前一篇文章我们已经学习到了使用Electron来构建我们的文件浏览器了基础东西了,我们之前已经完成了界面功能和显示文件或文件夹的功能了,想看之前文章,请点击这个链接  .现在我们需要在之前的基础上来 ...

  9. chrome如何查看cookie

    以mac为例: 第一步:点击chrome的偏好设置 第二步:点击如下图所示的最下面的高级 第三步:点击内容设置,如下所示 第四步:点击cookie,就会出现查看所有cookie和网站数据

  10. 用户点击获取验证码之后我们会发送一条信息到用户手机,然后就会出现一个倒计时按钮,很像支付宝手机付款效果了,下面我给大家分享两个js效果

    js代码  代码如下 复制代码 <div class="input">    <input type="button" id="bt ...