[POJ1151][HDU1542]Atlantis(线段树,扫描线)
英文题面,我就只放个传送门了。
Solution
题意是算矩形面积并,这是扫描线算法能解决的经典问题。
算法的大致思想是,把每一个矩形拆成上边和下边(以下称作扫描线),每条扫描线有四个参数l,r,h,v。l和r为它的左右端点的横坐标,h为扫描线的纵坐标,v下面再解释。
然后把扫描线按h从小到大排序,想一想,所有相邻扫描线之间的有效面积(即被矩形覆盖的面积)加起来是不是就是ans?
怎么求呢?我们从下往上处理,设当前处理到第i条扫描线,设第i条扫描线与第i+1条扫描线之间的有效面积为s,那么s=(h[i+1]-h[i])*此时x轴被覆盖的长度。
考虑用线段树来维护这个“x轴被覆盖的长度“,处理到第i条扫描线时,就把区间[l[i],r[i]]覆盖一次。但是这个覆盖是有时限的,当扫到某一条上边时,它对应的下边所产生的覆盖就应该被消去。
为了方便地处理,我们把下边的v值设为1,上边的v值设为-1,这样修改时直接把区间[l[i],r[i]]的覆盖次数加v就好了。
具体实现时,x坐标要离散化,线段树中用cnt来表示区间被覆盖的次数,sum来表示区间(当然都是在x轴上)内的覆盖长度。
注意两点:
- 线段树上一个叶子节点i实际上表示的是x轴上[i,i+1]这一段,因此线段树只需要n-1个叶子节点。
- 由于我们只需要查询sum[1],所以update找到需修改的区间可以直接pushup,并且不用pushdown。
Code
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- const int N=;
- struct line{
- double l,r,h;int v;
- line(){}
- line(double a,double b,double c,int d):l(a),r(b),h(c),v(d){}
- bool operator < (const line &tmp)const{return h<tmp.h;}
- }L[N];
- int cnt[N<<];
- double X[N],sum[N<<];
- #define tl id<<1
- #define tr id<<1|1
- #define mid ((l+r)>>1)
- #define lson tl,l,mid
- #define rson tr,mid+1,r
- void pushup(int id,int l,int r){
- if(cnt[id]) sum[id]=X[r+]-X[l];
- else if(l==r) sum[id]=;
- else sum[id]=sum[tl]+sum[tr];
- }
- void update(int id,int l,int r,int ll,int rr,int v){
- if(ll<=l&&r<=rr){
- cnt[id]+=v;
- pushup(id,l,r);
- return ;
- }
- if(ll>mid) update(rson,ll,rr,v);
- else if(rr<=mid) update(lson,ll,rr,v);
- else update(lson,ll,rr,v),update(rson,ll,rr,v);
- pushup(id,l,r);
- }
- int n,m,cas;
- int main(){
- while(~scanf("%d",&n)&&n){
- m=;memset(cnt,,sizeof cnt);memset(sum,,sizeof sum);
- for(int i=;i<n;++i){
- double a,b,c,d;
- scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
- L[m]=line(a,c,b,);
- X[m++]=a;
- L[m]=line(a,c,d,-);
- X[m++]=c;
- }
- sort(&L[],&L[m]);
- sort(&X[],&X[m]);n=unique(&X[],&X[m])-X;
- double s=;
- for(int i=;i<m;++i){
- int l=lower_bound(&X[],&X[n],L[i].l)-X,r=lower_bound(&X[],&X[n],L[i].r)-X-;
- update(,,n-,l,r,L[i].v);
- s+=sum[]*(L[i+].h-L[i].h);
- }
- printf("Test case #%d\nTotal explored area: %.2lf\n\n",++cas,s);
- //POJ上提交G++的同学请改为%.2f
- }
- return ;
- }
扫描线
[POJ1151][HDU1542]Atlantis(线段树,扫描线)的更多相关文章
- hdu1542 Atlantis 线段树--扫描线求面积并
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
- HDU 1542 - Atlantis - [线段树+扫描线]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...
- POJ1151 Atlantis 线段树扫描线
扫描线终于看懂了...咕咕了快三个月$qwq$ 对于所有的横线按纵坐标排序,矩阵靠下的线权值设为$1$,靠上的线权值设为$-1$,然后执行线段树区间加减,每次的贡献就是有效宽度乘上两次计算时的纵坐标之 ...
- HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- 【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- POJ 1151 - Atlantis 线段树+扫描线..
离散化: 将所有的x轴坐标存在一个数组里..排序.当进入一条线段时..通过二分的方式确定其左右点对应的离散值... 扫描线..可以看成一根平行于x轴的直线..至y=0开始往上扫..直到扫出最后一条平行 ...
- POJ 1151:Atlantis 线段树+扫描线
Atlantis Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19374 Accepted: 7358 Descrip ...
- hdu 1542 Atlantis (线段树扫描线)
大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...
- hdu1542 Atlantis (线段树+矩阵面积并+离散化)
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
随机推荐
- CF10D-LCIS题解--线性DP+打印方案
题目链接: https://www.luogu.org/problemnew/show/CF10D 方法一 分析 \(LCS\)和\(LIS\)已经成烂大街的知识了,可是当这两个合并起来成为\(LCI ...
- Eclipse 快捷键、文档注释、多行注释的快捷键
关于快捷键 Eclipse 的很多操作都提供了快捷键功能,我们可以通过键盘就能很好的控制 Eclipse 各个功能: 一.多行注释快捷键 1.选中你要加注释的区域,用ctrl+shift+C 或者ct ...
- 【ExtJs】在Ext.grid.Panel中,两列的值相乘作为第三列的值的实现
如: 商品总价=商品单价*商品数量 方法: 商品总价列,使用其renderer属性,为期定义一个方法,该方法将当前record中的另外两列中2个数据相乘后渲染到该商品总价列.
- 修改this的指向
call var a={ name:'xuux', fn:function(a,b){ console.log(a+b); console.log(this);//{name: "xuux& ...
- Repeater循环页面上的控件
List<string> list = new List<string>(); for (int k = 0; k < RepeaterList.Items.Count; ...
- Kubernetes介绍与核心组件
Kubernetes是什么? Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署.自动扩缩容.维护等功能. Kubernetes 特点 可移植: 支持公有云,私有云 ...
- mybatis框架中 #和$传递参数的区别 和注意
#{}: 1. 是预编译 2. 编译成占位符 3. 可以防止sql注入 4. 自动判断数据类型 5. 一个参数时,可以使用任意参数名称进行接收 ${}: 1. 非预编译 2. sql的直 ...
- BLE 5协议栈-通用属性规范层(GATT)
文章转载自:http://www.sunyouqun.com/2017/04/page/2/ 通用属性规范GATT(Generic Attribute Profile)将ATT层定义的属性打包成不同的 ...
- django 百度分页算法
效果如下: 脚本: 1. 脚本结构 2.pagination.py from django.utils.safestring import mark_safe class Page: ''' curr ...
- Java-20180412
今天开始重新复习Java,完成了leetcode的第一题. 1.算法: 给定一个数组和目标值,找出相加等于目标值的数组元素的下标. 数组[2,7,11,15]; target:9; 返回:[0,1]; ...