线段树扫描线(hdu1542)

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.

InputThe 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.OutputFor 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 就是给定你2若干个矩形,求覆盖的面积。看数据范围,就要用离散化来做,我们可以使用扫描线,沿着x轴扫过去,将每一个x坐标所对应的y的上下界用线段树表示出来,当一个矩形入边加入的时候就+1,否则就-1,然后算出面积就可以了。具体看代码,我写了一些较为详细的注释。
#pragma GCC optimize("O2")
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<ctype.h>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+(r-l)/2)
#define maxn 500
#define LL long long
using namespace std;

struct TREE{int l,r,c;double cnt,lf,rf;}tr[maxn*4];//l,r存线段树的下标,c存+1-1,就是这颗扫描线扫过的矩形的数量,cnt存答案,也就是一段区间,lf,rf为区间的左右界
struct Line{double x,y1,y2;int c;}line[maxn];
int m=0,n;
double y[maxn];
bool cmp(Line a,Line b){return a.x<b.x;}

void build(int l,int r,int rt)//离散化,坐标一一对应
{
	tr[rt].l=l;tr[rt].r=r;
	tr[rt].cnt=tr[rt].c=0;
	tr[rt].lf=y[l],tr[rt].rf=y[r];
	if(l+1==r) return;//左闭右开的区间
	build(l,mid,ls);
	build(mid,r,rs);//同上所以不是mid+1
}//说一下区间为什么要 左闭右开,因为这样在计算面积的时候就不用+1-1,就不会出现细节上的错误 

void getlen(int rt)
{
	if(tr[rt].c)
	{
		tr[rt].cnt=tr[rt].rf-tr[rt].lf;
	//	tr[rt].c=0;//注意这里不能清空,应该在下一条出边加入的时候才能清空
		return ;
	}
	if(tr[rt].l+1==tr[rt].r) tr[rt].cnt=0;//如果是一个节点而不是区间
	else tr[rt].cnt=tr[ls].cnt+tr[rs].cnt;
	return ;
}

void update(int rt,Line e)
{
	if(e.y1==tr[rt].lf&&e.y2==tr[rt].rf)
	{
		tr[rt].c+=e.c;
		getlen(rt);
		return ;
	}
	if(e.y2<=tr[ls].rf) update(ls,e);//左儿子和右儿子要分开计算
	else if(e.y1>=tr[rs].lf) update(rs,e);
	else
	{
		Line tmp=e;
		tmp.y2=tr[ls].rf; update(ls,tmp);
		tmp=e;
		tmp.y1=tr[rs].lf; update(rs,tmp);
	}
	getlen(rt);
}

void input()
{
	double x1,x2,y1,y2;
	for(int i=1;i<=n;i++)
	{
		cin>>x1>>y1>>x2>>y2;
		line[++m].x=x1;line[m].y1=y1;line[m].y2=y2;line[m].c=1;
		y[m]=y1;
		line[++m].x=x2;line[m].y1=y1;line[m].y2=y2;line[m].c=-1;
		y[m]=y2;
	}
	sort(line+1,line+m+1,cmp);
	sort(y+1,y+m+1);//坐标离散化
}
void init()//记得初始化
{
	memset(tr,0,sizeof(tr));
	m=0;
	memset(line,0,sizeof(line));
	memset(y,0,sizeof(y));
}

int main()
{
	int kase=0;
	while(cin>>n&&n)
	{
		init();
		input();
		build(1,m,1);
		update(1,line[1]);//先加入第一条线
		double ans=0;
		for(int i=2;i<=m;i++)
		{
			ans+=tr[1].cnt*(line[i].x-line[i-1].x);//标准的面积计算公式
			update(1,line[i]);
		}
		printf("Test case #%d\n", ++kase);
		printf("Total explored area: %.2lf\n\n",ans);
	}
	return 0;
}
/*
2
1 1 3 3
2 2 4 4
*/
时间: 2024-10-08 19:55:08

线段树扫描线(hdu1542)的相关文章

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

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9032    Accepted Submission(s): 3873 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

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

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 18559    Accepted Submission(s): 7523 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋.后来看了一位朋友的题解,才幡然醒悟. 开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示.那么就可以用十进制1~7表示7种不同颜色了. 维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长

sgu316Kalevich Strikes Back(线段树+扫描线)

做法:总体想法是求出一个矩形的面积以及它所包含的矩形,然后用自己的面积减掉所包含的.主要问题是怎样求解它所包含的矩形. 因为是没有相交点的,可以利用扫描线的方法去做,类似染色,当前段如果是x色,也就是第x个矩形,那么再把他染成y颜色时,说明x包含y,而当扫到y的上边时,这一段又恢复到x色.标记一下被包含的矩形,记录所包含的矩形. 因为会有恢复染色操作,up需要时时更新,左儿子和右儿子一样颜色时就可以合并为一段. 1 ; 2 } 3 void down(int w) 4 { 5 if(s[w]!=

hdu1255 覆盖的面积 线段树-扫描线

矩形面积并 线段树-扫描线裸题 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<math.h> 5 using namespace std; 6 const int maxm=2e3+5; 7 const double eps=1e-5; 8 9 struct seg{ 10 double x,y1,y2; 11 int c; 12 bool operator

线段树+扫描线 HDOJ 5091 Beam Cannon

题目传送门 1 /* 2 题意:给出若干个点的坐标,用一个矩形去覆盖,问最多能覆盖几个点 3 线段树+扫描线:思路是先建一棵以[y, y + h]的树,左右儿子[x, x + w] 4 以这棵树为范围,从左到右扫描,更新点数,x的+1, x+w的-1(超过矩形范围) 5 ans = 每次更新时所覆盖点数的最大值 6 */ 7 #include <cstdio> 8 #include <algorithm> 9 #include <iostream> 10 #includ

POJ 3277 City Horizon(线段树+扫描线+离散化)

题目地址:POJ 3277 水题..稍微处理一下然后用求面积并的方法求即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <