ACM: 线段树 poj 1151 足足想了三…
2016-05-19 23:23
435 查看
Atlantis
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.
Sample Input
Sample Output
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.
Sample Input
2 10 10 20 20 15 15 25 25.5 0
Sample Output
Test case #1 Total explored area: 180.00 题意: 计算矩形的面积, 矩形之间重叠的部分只能算一次. 解题思路:
1. 在坐标范围中, 一般的方法都是"离散化": 将出现过的点, 把平面分成网格形状, 每个矩形大小不一.
2. 思路同黑书上"金矿"思路相似, 只需要从左到右每次将一条垂直与X轴的竖边插入线段树中,
并且计算当前前后两条竖边夹的面积, 当然夹的面积可能为0.
3. 先将输入的矩形的两条竖边保存, 并且按照X的大小从左到右排序. 以便从左到右插入. 而且,
矩形的Y坐标保存起来从小到大排序, 为建树准备区间范围.
线段树分析:
建树: 插入的单位是一条竖边, 是对Y坐标进行二分建树. 并且我们设置一个flag标记来判断,
矩形的进入和退出, 分别是+1和-1. 因为事先我们都知道全部的边的范围.
举个例子: 用题目给出的例子. 如下图:
树是建好了,怎么使用它来帮助我们计算面积呢?两条竖边怎么计算矩形面积?
每两条矩形的长可以简单的line[i].x-line[i-1].x即可.(X轴差值). 那么矩形的高,
我们就要在线段树每个区间设置一个变量len, 表示每插入一条边之后当前夹成的矩形的宽. 分成三个矩形计算面积了. 插入竖边: 每次插入时如果当前区间被完全覆盖,那么就要对 flag 进行更新入边 +1 出边 -1,
更新后判断当前节点的 flag 是否大于 0, 如果大于 0,那么当前节点的 len就是节点
所覆盖的区间. 否则,如果是叶子节点,则 len=0,如果内部节点,则 len=左右儿子的 len 之和.
(这个过程可以形象看成是上面1,2,3三个矩形, 插入和删除过程).
4. 收获不少这题. 线段树+离散化. 代码: #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> using namespace std; #define MAX 1005 struct Line { double x, y1, y2; int flag; }line[MAX]; struct node { int left, right; double l, r, len; int flag; }pt[MAX]; int n; double x1, x2, y1, y2; int num; double y[MAX]; int cmp1(const void *a, const void *b) { if(*(double *)a > *(double *)b) return 1; else return -1; } int cmp2(const void *a, const void *b) { if( (*(Line *)a).x > (*(Line *)b).x ) return 1; else return -1; } void insertLength(int pos) { if(pt[pos].flag > 0) pt[pos].len = (pt[pos].r - pt[pos].l); else if( (pt[pos].left+1) == pt[pos].right ) pt[pos].len = 0; else pt[pos].len = (pt[pos*2].len + pt[pos*2+1].len); } void buildTree(int l, int r, int pos) { pt[pos].left = l, pt[pos].right = r; pt[pos].l = y[l], pt[pos].r = y[r]; pt[pos].len = pt[pos].flag = 0; if( (l+1) == r ) return ; int mid = (l+r)/2; buildTree(l, mid, pos*2); buildTree(mid, r, pos*2+1); } void insert(Line e, int pos) { if(pt[pos].l == e.y1 && pt[pos].r == e.y2) { pt[pos].flag += e.flag; insertLength(pos); return ; } if(e.y1 >= pt[pos*2+1].l) insert(e, pos*2+1); else if(e.y2 <= pt[pos*2].r) insert(e, pos*2); else { Line temp = e; temp.y2 = pt[pos*2].r; insert(temp, pos*2); temp = e; temp.y1 = pt[pos*2+1].l; insert(temp, pos*2+1); } insertLength(pos); } int main() { int caseNum = 1; freopen("input.txt","r",stdin); while(scanf("%d",&n) != EOF && n != 0) { num = 1; for(int i = 1; i <= n; ++i) { scanf("%lf %lf %lf %lf",&x1, &y1, &x2, &y2); line[num].x = x1; line[num].y1 = y1; line[num].y2 = y2;
相关文章推荐
- ACM: 线段树 poj 2352
- ACM: 最小堆 poj 2274 思路清晰, …
- ACM: 最小堆 poj 2227 最小堆 fro…
- ACM: 划分树 poj 2761 在poj2104基…
- ACM: 动态规划题 poj 1036 问题简…
- ACM: 动态规划题 poj 2033 (博客好…
- 包装类
- ARM (三) arm中C/C++及汇编语言的…
- ARM (二) arm指令分类及其寻址方式
- ARM (一) arm寄存器
- ACM:动态规划题 poj 1015
- ACM:计划一个公司聚会 (大一时头疼…
- 计算几何:正多边形的滚动与旋轮线…
- 学习心得:《十个利用矩阵乘法解决…
- ACM: 矩阵变形题 数论题 poj 3150
- SeaJS与RequireJS最大的区别
- ACM: 二分又二分 数论题 poj 3233
- ACM: 矩阵建模 数论题 poj 3735 (…
- ACM: 经过K条边的最短路 图论题 po…
- ACM: 矩阵快速幂运算 数论题 poj 3…