亚特兰蒂斯【线段树+扫描线+离散化】

POJ1151ACwing247

题目:

有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述。

其中一些甚至包括岛屿部分地图。

但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。

您的朋友 Bill 必须知道地图的总面积。

你自告奋勇写了一个计算这个总面积的程序。

输入格式:

输入包含多组测试用例。

对于每组测试用例,第一行包含整数 nn,表示总的地图数量。

接下来 n 行,描绘了每张地图,每行包含四个数字 x1,y1,x2,y2(不一定是整数),(x1,y1) 和 (x2,y2) 分别是地图的左上角位置和右下角位置。

注意,坐标轴 x 轴从上向下延伸,y 轴从左向右延伸。

注意这里的提示,也就是我们正常理解的左下角和右上角

当输入用例 n=0 时,表示输入终止,该用例无需处理。

输出格式:

每组测试用例输出两行。

第一行输出 Test case #k,其中 k 是测试用例的编号,从 1 开始。

第二行输出 Total explored area: a,其中 a 是总地图面积(即此测试用例中所有矩形的面积并,注意如果一片区域被多个地图包含,则在计算总面积时只计算一次),精确到小数点后两位数。

在每个测试用例后输出一个空行。

数据范围:

1≤n≤10000,
0≤x1<x2≤100000,
0≤y1<y2≤100000
注意,本题 n 的范围上限加强至 10000。

样例输入:

2
10 10 20 20
15 15 25 25.5
0

样例输出:

Test case #1
Total explored area: 180.00 

思路:

如果y轴离散化后数组为ys[5.1,6.2,8.5,10.8]

我们假设线段树内的结点[1,1]、[2,2]的父节点是[1,2],若要[1,2]这个结点的len能够映射离散化区间里面的8.5、6

2。但是如果根节点是[0,2],要查询[1,2]的长度len,就会将[0,2]分成[0,1]和[2,2],这样就把要求的区间砍断了。

所以采用另外一种映射方法。将区间[0,0]映射到5.16.5,[1,1]映射到6.28.5。那么线段树的最小单位就是一个长度而不是一个点了,也就是:[l,r]的长度=ys[r+1]-ys[l]。

主要就是离散化过后让线段树的每个结点的y轴不存在交叉,然后y轴的宽度累加乘以x扫过的距离,再对该乘积进行累加,就是最终的面积了。

代码:

#include<bits/stdc++.h>
using namespace std;#define int long long
const int N = 1e4+5;int n;
//--------------------------------------
struct Node{int l,r;        //存储区间int count;      //当前区段被有效覆盖的次数double len;     //当前区段内的有效长度
} tree[N << 3];    //存储线段树
//--------------------------------------
struct edge{double x,y1,y2; //三个坐标int k;          //1表示是矩形左边的线,-1表示是矩形右边的线
} E[N << 1];        //存储边
int k;              //存储一共有多少条边
//--------------------------------------
vector<double> v;   //用于离散化bool cmp(edge a,edge b){return a.x < b.x;
}void pushup(int p){//如果该结点的一整段[l,r]都需要算入的话,就直接查找离散化后的表v就行if(tree[p].count)tree[p].len = v[tree[p].r + 1] - v[tree[p].l];//没有全部覆盖那么就是左右孩子的有效长度相加else if(tree[p].count == 0 && tree[p].l != tree[p].r)tree[p].len = tree[p<<1].len + tree[p<<1|1].len;//该最小片段未被选中elsetree[p].len = 0;
}void build(int p,int l,int r){tree[p] = {l,r,0,0};if(l == r)return;int lc = p<<1,rc = p<<1|1,mid = l+r>>1;build(lc,l,mid);build(rc,mid + 1,r);pushup(p);
}void update(int p,int l,int r,int k){//第一次遇到这条边,count+1有效,而如果是第二次遇到,那么久-1无效if(tree[p].l == l && tree[p].r == r)tree[p].count += k;else{int lc = p<<1,rc = p<<1|1,mid = tree[p].l+tree[p].r>>1;if(r<=mid)update(lc,l,r,k);else if(l > mid)update(rc,l,r,k);elseupdate(lc,l,mid,k),update(rc,mid + 1,r,k);}pushup(p);
}int find_w(double x){return lower_bound(v.begin(),v.end(),x) - v.begin();
}signed main(){int T = 0;while(cin>>n && n){k = 0;v.clear();cout<<"Test case #"<<++T<<"\n";double x1,y1,x2,y2;double ans = 0;for(int i = 1;i <= n;++i){cin>>x1>>y1>>x2>>y2;E[k].x = x1;E[k].y1 = y1,E[k].y2 = y2,E[k++].k = 1;E[k].x = x2;E[k].y1 = y1,E[k].y2 = y2,E[k++].k = -1;v.push_back(y1),v.push_back(y2);        //存储一个矩形的两条边,并且为离散化做准备}sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end()); //去重离散化build(1,0,v.size() - 2);            //建立线段树sort(E,E + k,cmp);                      //将所有的线按照x从左到右进行排序,以便后续扫描for(int i = 0;i < k;++i){if(i > 0)ans += tree[1].len * (E[i].x - E[i-1].x);update(1,find_w(E[i].y1),find_w(E[i].y2) - 1,E[i].k);}
//        cout<<"Total explored area: "<<ans<<"\n\n";printf("Total explored area: %.2lf\n\n",ans);}return 0;
}

亚特兰蒂斯【线段树+扫描线+离散化】相关推荐

  1. 2016 UESTC Training for Data Structures F - 郭大侠与“有何贵干?” CDOJ 1335 线段树 扫描线 离散化

    F - 郭大侠与"有何贵干?" 就是给一个三维空间,和N个长方体,问覆盖K次的体积 x和y都是1e9,但是z是[1,3],所以可以把这个分为两个二维平面,求被覆盖K次的面积,最后加 ...

  2. 线段树 + 扫描线 + 离散化:亚特兰蒂斯

    题目链接:https://www.acwing.com/problem/content/description/249/ 题目: 有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述. 其中一些甚至包 ...

  3. POJ1151-Atlantis【线段树,扫描线,离散化】

    正题 题目链接:http://poj.org/problem?id=1151 题目大意 有n个矩形,求所以矩形的覆盖面积. 解题思路 我们用离散化一个坐标,然后每次用线段树维护这个宽度内覆盖高度和,然 ...

  4. 610D - Vika and Segments(线段树+扫描线+离散化)

    扫描线:http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html 看图,图中的数字是横坐标离散后对应的下标,计算时左端点不 ...

  5. POJ2482-Stars in Your Window【线段树,扫描线,离散化】

    正题 题目链接:http://poj.org/problem?id=2482 题目大意 有若干个点,每个点有不同的权值,求用一个h*w的矩阵扩起来的权值最大. 解题思路 先离散化一个坐标,然后另一个坐 ...

  6. hdu1542 线段树扫描线求矩形面积的并

    题意:       给你n个正方形,求出他们的所占面积有多大,重叠的部分只能算一次. 思路:       自己的第一道线段树扫描线题目,至于扫描线,最近会写一个总结,现在就不直接在这里写了,说下我的方 ...

  7. hdu 1542 Atlantis (线段树+扫描线)

    http://acm.hdu.edu.cn/showproblem.php?pid=1542 单纯的线段树+扫描线求面积并,需要离散化. code: #include <cstdlib> ...

  8. HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

    版权声明:欢迎关注我的博客.本文为博主[炒饭君]原创文章,未经博主同意不得转载 https://blog.csdn.net/a1061747415/article/details/25471349 P ...

  9. 线段树扫描线求矩形周长详解

    线段树扫描线求矩形周长详解 原创 wucstdio 最后发布于2018-04-24 16:12:09 阅读数 841 收藏 发布于2018-04-24 16:12:09 版权声明:本文为博主原创文章, ...

最新文章

  1. python 比较矩阵对应位置元素大小,比较矩阵的两个元素并在不同位置填充相对值...
  2. java map判断是否有键_检查Java HashMap中是否存在给定键
  3. oracle adg切换原理,oracle11g ADG主备切换
  4. python怎样分析文献综述怎么写_怎么写文献综述?
  5. Spark踩坑记——数据库(Hbase+Mysql)转
  6. 用Swift完成不同View Controller之间的切换
  7. set/multiset容器
  8. IDEA快捷键整理(最详细的)
  9. 语文学科html代码,2016年最新学科分类与代码..doc
  10. 虚拟机器系统安装管理 Xencenter
  11. 拼多多砍价小程序源码/流量主系列微信小程序源码
  12. 多系统对接的实现方案
  13. 解决硬盘打不开的问题
  14. 操作系统应用阶层现状,对操作系统的认识
  15. 书摘:别做正常的傻瓜
  16. Scrapy spiders介绍
  17. C语言for括号后加分号,在C语言中,for语句的后面加分号和不加分号有何不同?...
  18. 博士毕业评上副教授后,我打算直接躺平!
  19. 手指和手势识别算法原理和解析
  20. 1624. 地铁地图

热门文章

  1. 【修复日常bug】京东富文本详情图变形的多种处理方式(解决商品详情图片宽高不适应问题)
  2. FOJ 1021 飞船赛
  3. xxl-job基本使用
  4. sax dom html解析xml,Python通过DOM和SAX方式解析XML的应用实例分享
  5. 【设计模式学习笔记】组合模式与桥接模式案例详解(C++实现)
  6. 异步调用RFC:CALL FUNCTION ‘ZXXXXXXXXX‘ IN UPDATE TASK
  7. 电商在线支付学习摘录
  8. 传奇服务端初次使用极限插件必看步聚
  9. MySql基础学习笔记(一)
  10. AngularJS/Angular官网