欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Atlantis HDU - 1542 扫描线模板

程序员文章站 2022-06-08 14:08:27
...

一、内容

 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 file 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 

二、思路

  • 区间更新 + 离散化
  • Atlantis HDU - 1542 扫描线模板
  • 区间更新(优化): 由于我们增加和删除操作是成对出现的,且操作的区间相同,那么我们就不用pushdown()进行懒标记下方,因为我们用的区间是一定的,不会用到以前没有用过的区间。那么就不存在标记下方操作了。

三、代码

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 205;
struct Line {
	int st; //代表1 -1 2种状态 
	double s, e, x;
	bool operator < (const Line & w) const {
		return x < w.x; //按照x小的排在前面 
	}
} line[N];
struct Node {
	int cnt; //代表被包含的次数 
	double len; //这个区间被包含的长度 
} tr[N << 2]; 
int n, cnt, t = 1; // cnt代表离散化后数组里面元素的个数 
double fy[N], x1, x2, y1, y2; 
void build(int id, int l, int r) {
	tr[id].cnt = tr[id].len = 0;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(id << 1, l, mid);
	build(id << 1 | 1, mid + 1, r);
}
void pushup(int id, int l, int r) {
	if (tr[id].cnt){ // 代表id这个区间被覆盖了  
		tr[id].len = fy[r + 1] - fy[l]; //因为一个点代表的是一个区间 那r这个点的区间 就是[fy[r], fy[r + 1]]这段长度 
	} else if (l != r){ //如果这整个区间没有被包含 那么就由儿子区间组成 
		tr[id].len = tr[id << 1].len + tr[id << 1 | 1].len; 
	} else tr[id].len = 0; //叶子结点  
}
void update(int id, int l, int r, int x, int y, int d) {
	if (x <= l && r <= y) {
		tr[id].cnt += d;
		pushup(id, l, r); //及时更新这段区间 因为父亲区间可能需要用到我这个区间的len 
		return;
	}
	int mid = (l + r) >> 1;
	if (x <= mid) update(id << 1, l, mid, x, y, d);
	if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, d);
	pushup(id, l, r); 
} 
int  find(double y) {
	return lower_bound(fy + 1, fy + 1 + cnt, y) - fy; 
}
int main() {
	while (scanf("%d", &n), n) {
		for (int i = 1, j = 1; i <= n; i++) {
			scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
			line[j].s = y1, line[j].e = y2, line[j].x = x1, line[j].st = 1, fy[j++] = y1;
			line[j].s = y1, line[j].e = y2, line[j].x = x2, line[j].st = -1, fy[j++] = y2;
		}
		sort(line + 1, line + 1 + 2 * n);
		sort(fy + 1, fy + 1 + 2 * n);
		cnt = unique(fy + 1, fy + 1 + 2 * n) - fy - 1; //获取去重后元素的个数
		build(1, 1, cnt - 1); //一个点代表的是一个区间, 一共有cnt个点 所以只有cnt-1个区间
		double ans = 0;
		for (int i = 1; i <= 2 * n; i++) {
			ans += tr[1].len * (line[i].x - line[i - 1].x);
			update(1, 1, cnt - 1, find(line[i].s), find(line[i].e) - 1, line[i].st); //这里-1是因为每个点代表的是一个区间 我们不能包含e那个点所代表的区间 
		} 
		printf("Test case #%d\nTotal explored area: %.2lf\n\n", t++, ans); 
	}
	return 0;
}
相关标签: 线段树 HDU