POJ1151 Atlantis 【扫描线】+【线段树】+【离散化】

Atlantis

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 16882   Accepted: 6435

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 

我累个去~~这题从早上8:30一直做到现在22:50,总算是A掉了,上午一直没看懂扫描线,然后看到傍晚总算是有些头目了,结果写的时候很生疏,等到摸摸索索完完全全地写完已经大半夜了,满心欢喜地提交又各种RE,开始以为是数组开小了,然后翻了倍依旧RE,就这样RE了6、7次后猛地发现是freopen忘了注释掉,o(╯□╰)o...尼玛啊!!总归是在睡觉前找到问题了。

题意:给定n个矩形的对角坐标,分别是左下和右上,浮点型,求矩形覆盖的面积。

题解:扫描线解法,将每个矩形分别以长宽为直线分割,最终垂直于x轴的割线有2n条,垂直于y轴的割线也有2n条,将这些割线存到两个数组里并排序,建立一个线段树用以维护扫描线当前在y轴方向覆盖的长度,最后,在扫描线从左往右扫描的过程中,一旦经过一条垂直于x轴的割线就立马将这条割线更新到线段树里,覆盖面积即为两条相邻扫描线的距离乘以左边一条扫描线的长度,累加下去即得最终覆盖面积。x轴割线数组需要记录边是入边还是出边,若是出边则右边的的面积对此出边是不计的,但是存在入边重合的情况,需要具体考虑。

#include <stdio.h>
#include <algorithm>
#define maxn 202
#define lson l, mid, rt << 1
#define rson mid, r, rt << 1 | 1
using std::sort;

struct Node{
	double y1, y2, height; //y1, y2记录y坐标离散前的值
	int coverTimes;
} tree[maxn << 2]; //区间树
double yArr[maxn]; //垂直于Y轴的割线
struct node{
	double x, y1, y2;
	int isLeftEdge;
} xArr[maxn]; //垂直于X轴的割线

bool cmp(node a, node b){ return a.x < b.x; }

void build(int l, int r, int rt)
{
	tree[rt].coverTimes = 0;
	tree[rt].height = 0;
	tree[rt].y1 = yArr[l];
	tree[rt].y2 = yArr[r];
	if(r - l == 1) return;

	int mid = (l + r) >> 1;
	build(lson);
	build(rson);
}

void getSweepLinesHeight(int l, int r, int rt)
{//由于存在线段覆盖的情况,所以长线段结束并不能代表扫描线长度为0
	if(tree[rt].coverTimes > 0){
		tree[rt].height = tree[rt].y2 - tree[rt].y1;
	}else if(r - l == 1){
		tree[rt].height = 0;
	}else tree[rt].height = tree[rt << 1].height + tree[rt << 1 | 1].height;
}

void update(node xNode, int l, int r, int rt)
{
	if(xNode.y1 == tree[rt].y1 && xNode.y2 == tree[rt].y2){
		tree[rt].coverTimes += xNode.isLeftEdge;
		getSweepLinesHeight(l, r, rt);
		return;
	} //include r - l == 1

	int mid = (l + r) >> 1;
	if(xNode.y2 <= yArr[mid]) update(xNode, lson);
	else if(xNode.y1 >= yArr[mid]) update(xNode, rson);
	else{
		node temp = xNode;
		temp.y2 = yArr[mid];
		update(temp, lson);
		temp = xNode; temp.y1 =yArr[mid];
		update(temp, rson);
	}

	getSweepLinesHeight(l, r, rt); //Attention!
}

int main()
{
	//freopen("stdin.txt", "r", stdin);
	int n, i, cas = 1, id;
	double x1, y1, x2, y2, sum;
	while(scanf("%d", &n), n){
		for(i = id = 0; i < n; ++i){
			scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
			yArr[id] = y1; xArr[id].x = x1;
			xArr[id].isLeftEdge = 1; //1表示左,-1表示右
			xArr[id].y1 = y1; xArr[id++].y2 = y2;

			yArr[id] = y2; xArr[id].x = x2;
			xArr[id].isLeftEdge = -1;
			xArr[id].y1 = y1; xArr[id++].y2 = y2;
		}

		sort(yArr, yArr + id);
		sort(xArr, xArr + id, cmp);
		build(0, id - 1, 1);		

		update(xArr[0], 0, id - 1, 1);
		for(i = 1, sum = 0; i < id; ++i){
			sum += tree[1].height * (xArr[i].x - xArr[i - 1].x);
			update(xArr[i], 0, id - 1, 1);
		}

		printf("Test case #%d\nTotal explored area: %.2lf\n\n", cas++, sum);
	}
	return 0;
}

POJ1151 Atlantis 【扫描线】+【线段树】+【离散化】

时间: 2024-08-29 19:34:34

POJ1151 Atlantis 【扫描线】+【线段树】+【离散化】的相关文章

poj1151 Atlantis——扫描线+线段树

题目:http://poj.org/problem?id=1151 经典的扫描线问题: 可以用线段树的每个点代表横向被矩形上下边分割开的每一格,这样将一个矩形的出现或消失化为线段树上的单点修改: 每个格子记录两个值:c(矩形存在情况),sum(对当前答案作出贡献的长度): 将y离散化作为建树的依据: 一开始没想到线段树上的点应该是横向的格子,写了个乱七八糟: #include<iostream> #include<cstdio> #include<cstring> #i

POJ 1151 Atlantis 扫描线+线段树

点击打开链接 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17252   Accepted: 6567 Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &

HNU12884_Area Coverage(扫描线/线段树+离散化)

解题报告 题目传送门 题意: 又是求面积并 思路: 又是求面积并,还被坑了,题目明明描述的是int坐标,用了double才过... #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { double lx,rx,h; int v; friend bool operator <(Seg

【HDU 1542】Atlantis(线段树+离散化,矩形面积并)

求矩形面积并,离散化加线段树. 扫描线法: 用平行x轴的直线扫,每次ans+=(下一个高度-当前高度)*当前覆盖的宽度. #include<algorithm> #include<cstdio> #include<cstring> #define dd double #define ll long long #define N 201 using namespace std; struct P{dd s,e,h;int f;}p[N]; struct Tree{dd s

poj 1151 Atlantis (离散化 + 扫描线 + 线段树)

题目链接题意:给定n个矩形,求面积并,分别给矩形左上角的坐标和右上角的坐标. 分析: 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <cstdlib> 6 #include <algorithm> 7 #define LL __int64 8 #define lson l, mid, 2*rt

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

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

[POJ1151]Atlantis(线段树,扫描线) 题面 Vjudge 题解 学一学扫描线 其实很简单啦 这道题目要求的就是若干矩形的面积和 把扫描线平行于某个轴扫过去(我选的平行\(y\)轴扫) 这样只需要求出每次和\(x\)轴覆盖的长度 就可以两两相乘,求出面积 最后累计和就行啦 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cma

poj3277--City Horizon(线段树+离散化+扫描线)

City Horizon Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16206   Accepted: 4414 Description Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouette

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

Atlantis Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of pa