HDU 1542 Atlantis(离散化+扫描线(求并面积)+线段树)

题目点这里
贴个链接,链接在这里~,扫描线启蒙
------------------------------------------------------------------------------------------------------------------------------------------------------
题目大意:
有多组测试数据;
给出n个矩形的左下和右上的点的横纵坐标(%lf);
求这n个矩形的总面积不能重复计算;
------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
既然给的是浮点型(%lf)就先会想到离散;
求并面积那么就会想到用扫描线~~~~~~~~~;
扫描线可以从上下方向也可以左右,我比较倾向于上下啦;
因为自下往上扫,所以记录平行于x轴的矩形的边的各种信息(左右端点的坐标,出入(出为-1入为1),所对应的
y轴的坐标),以离散化后的x轴构建线段树;
只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的y定位 - 上一线
段的y定位)*(该区间的大小)
------------------------------------------------------------------------------------------------------------------------------------------------------
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;


struct node
{
	int l,r,cover;
	double left_x,right_x,temp_y;
}e[110*1000];
struct edge
{
	double y,left_x,right_x;
	int flag;
	bool operator < (const edge &a)const{return y < a.y;}
}line[110<<1];
double x[110<<1];
int cas,n,cnt;
double x1,x2,y1,y2;

void build(int k,int l,int r)
{
	e[k].l = l,e[k].r = r;
	e[k].left_x = x[l],e[k].right_x = x[r];
	e[k].cover = 0,e[k].temp_y = -1;
	if(l+1 == r)return;
	int mid = (l + r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid,r);
//注意这里不是mid+1我就栽在这里T_T,因为这样的话左儿子的右边无法与右儿子的左边计算 
}

double query(int k,double y,double l,double r,int flag)
{
	if(l >= e[k].right_x || r <= e[k].left_x)return 0;
	if(e[k].l + 1 == e[k].r)
	{
		if(e[k].cover)
		{
			double ans = (y - e[k].temp_y)*(e[k].right_x - e[k].left_x);
			e[k].temp_y = y;//定位这次扫描线的y坐标 
			e[k].cover += flag;
			return ans;
		}
		else
		{
			e[k].temp_y = y;
			e[k].cover += flag;
			return 0; 
		}
	}
	return query(k<<1,y,l,r,flag)+query(k<<1|1,y,l,r,flag);
}

int main()
{	
	while(scanf("%d",&n)!=EOF && n)
	{
		cnt = 0;
		for(int i = 1;i <= n;i++)//记录每条扫描线的各种信息 
		{
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
			line[++cnt].left_x = x1;
			line[cnt].right_x = x2;
			line[cnt].y = y1;
			line[cnt].flag = 1;
			x[cnt] = x1;
			
			line[++cnt].left_x = x1;
			line[cnt].right_x = x2;
			line[cnt].y = y2;
			line[cnt].flag = -1;
			x[cnt] = x2;
		}
		sort(x+1,x+cnt+1);
		sort(line+1,line+cnt+1);//离散操作 
		build(1,1,cnt);//以离散后的x轴建立坐标 
		double ans = 0;
		for(int i = 1;i <= cnt;i++)
		ans += query(1,line[i].y,line[i].left_x,line[i].right_x,line[i].flag);//开始扫描 
		printf("Test case #%d\nTotal explored area: %.2f\n\n", ++cas, ans);
	}
	return 0;
}
刷题感悟:
建树做注意事项;
扫描线的3个作用之一:求并面积;
熟练掌握链接里面的第二种方法!

------------------------------------------------------------------------------------------------------------------------------------------------------
这是一道很裸的扫描线求并面积的题,欢迎去刷~








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值