HDU 1542 - Atlantis - [线段树+扫描线]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
题意:
给出n个矩形的左下角和右上角坐标,保证矩形面积大于零,要求n个矩形所覆盖的整个图形的面积。
题解:
属于线段树配合扫描线的模板题,
转载自https://blog.csdn.net/konghhhhh/article/details/78236036的线段树+扫描线基本原理:
假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形……多个矩形叠加后的那个图形)。
如果是竖直方向上扫描,则是离散化横坐标,如果是水平方向上扫描,则是离散化纵坐标。下面的分析都是离散化横坐标的,并且从下往上扫描的。
扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值$-1$,下边给他一个值$1$,我们用一个结构体来保存所有的上下边:
struct Segment
{
double l,r,h; //l和r表示这条上下边的左右坐标,h是这条边所处的高度
int f; //所赋的值,1或-1
}
接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。
还记得给他们赋的值$1$或$-1$吗,下边是$1$,扫描到下边的话相当于往总区间插入一条线段,上边是$-1$,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增$1$,扫描到上边对应的那一段的值都要减$1$,如果总区间某一段的值为$0$,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。
每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积。

当然了,我们知道,线段树维护的是点,而这里我们要维护的是连续的区间,
因此我们给每个点赋予新的意义:对于第 i 个点,其代表区间 [ i , i+1 ),
然后,本题对横轴坐标进行去重离散化,假设最后剩下size个横坐标,存储在数组 x[1~size]中,那么我们线段树就从 点0 到 点size-1 建树,这样就能维护整个总区间,
同时我们也需要对线段树进行一定的修改,体现在代码中。
AC代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std; const int maxn=; int n; vector<double> x;
inline int getID(double val){return lower_bound(x.begin(),x.end(),val)-x.begin();} struct Segment
{
double l,r;
double h;
int flag;
}segment[maxn];
bool cmp(Segment a,Segment b){return a.h<b.h;} /********************************* Segment Tree - st *********************************/
struct Node{
int l,r;
int s;
double len;
}node[*maxn];
void pushup(int rt)
{
if(node[rt].s) node[rt].len=x[(node[rt].r+)]-x[(node[rt].l)];
else if(node[rt].l==node[rt].r) node[rt].len=;
else node[rt].len=node[rt*].len+node[rt*+].len;
}
void build(int rt,int l,int r)
{
if(l>r) return;
node[rt].l=l; node[rt].r=r;
node[rt].s=; node[rt].len=;
if(l==r) return;
else
{
int mid=l+(r-l)/;
build(rt*,l,mid);
build(rt*+,mid+,r);
pushup(rt);
}
}
void update(int root,int st,int ed,int val)
{
if(st>node[root].r || ed<node[root].l) return;
if(st<=node[root].l && node[root].r<=ed)
{
node[root].s+=val;
pushup(root);
}
else
{
update(root*,st,ed,val);
update(root*+,st,ed,val);
pushup(root);
}
}
/********************************* Segment Tree - st *********************************/ int main()
{
int kase=;
while(scanf("%d",&n) && n!=)
{
x.clear();
for(int i=;i<=n;i++)
{
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); Segment &s1=segment[*i-];
Segment &s2=segment[*i];
s1.l=s2.l=x1;
s1.r=s2.r=x2;
s1.h=y1;
s2.h=y2;
s1.flag=;
s2.flag=-; x.push_back(x1);
x.push_back(x2);
} sort(segment+,segment+*n+,cmp); //横坐标去重离散化
sort(x.begin(),x.end());
x.erase(unique(x.begin(),x.end()),x.end()); build(,,x.size());
double ans=;
for(int i=;i<=*n;i++)
{
int l=getID(segment[i].l);
int r=getID(segment[i].r);
update(,l,r-,segment[i].flag);
ans+=node[].len*(segment[i+].h-segment[i].h);
}
printf("Test case #%d\n",++kase);
printf("Total explored area: %.2f\n\n",ans);
}
}
HDU 1542 - Atlantis - [线段树+扫描线]的更多相关文章
- HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu 1542 Atlantis (线段树扫描线)
大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...
- hdu 1542 Atlantis(线段树,扫描线)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1542 Atlantis(线段树面积并)
描述 There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. S ...
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...
- Atlantis HDU - 1542 (线段树扫描线)
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
- hdu 1542(线段树+扫描线 求矩形相交面积)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- hdu 1542 Atlantis(段树&扫描线&面积和)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu1542 Atlantis 线段树--扫描线求面积并
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
随机推荐
- 【数据分析】Superset 之三 Docker操作管理
一.进入容器 查看运行的容器:docker ps docker attach confident_thompson 或者 docker attach 34cd2299110f docker exec ...
- C++开发--在Visual Studio2013中使用boost::split()编译过程中出现error C4996
Visual Studio is being overly cautious. In debug mode, visual studio uses something called "Ch ...
- firefox 好用的插件
firefox一直是各位渗透测试必备的利器,这里整理了34款Firefox插件和几款Chrome的插件,其中包含渗透测试.信息收集.代理.加密解密等功能. Firefox插件 1:Firebug Fi ...
- 使用 PyQuery
PyQuery 用法: (1) 前面我们爬取一个网页,都是使用正则表达式来提取想要的信息,但是这种方式比较复杂,一旦有一个地方写错,就匹配不出来了,因此我们可以使用 PyQuery(2) PyQuer ...
- 使用 Beautiful Soup
Beautiful Soup 用法: (1) 前面我们爬取一个网页,都是使用正则表达式来提取想要的信息,但是这种方式比较复杂,一旦有一个地方写错,就匹配不出来了,因此我们可以使用 Beautiful ...
- 据库分库分表(sharding)系列(一) 拆分实施策略和示例演示
本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sh ...
- Python中字符串的intern机制
intern机制: 字符串类型作为Python中最常用的数据类型之一,Python解释器为了提高字符串使用的效率和使用性能,做了很多优化,例如:Python解释器中使用了 intern(字符串驻留)的 ...
- WP8.1学习系列(第十七章)——交互UX之输入和反馈模式
如果你将 Windows 应用商店应用设计为触摸交互,则可免费获取对触摸板.鼠标.笔和键盘交互的支持.你的用户可以从一种输入法切换到另一种,而不会丧失应用体验的感觉.将键盘插入平板电脑?没问题.你的应 ...
- Material Design系列第一篇——Creating Apps with Material Design
Creating Apps with Material Design //创建Material Design的App Material design is a comprehensive guide ...
- 开始使用ARC
Automatic Reference Counting (ARC)是编译器自动管理Objective-C对象的一个功能,相对于不得不考虑retain和release操作来说,ARC让我们有更多的精力 ...