poj 1151 Atlantis (线段树扫描线)

题意:给你n个矩形的左下角和右上角的坐标,现在问你这个复合矩形的总面积

思路:这就是线段树扫描线的裸题,扫描线就是在你的复合矩形上面加上一条虚拟的线,其中有两种一种是从左往右的扫描线,一种是从下到上的,这里我写的是从下到上的扫描线,先上图把


<来源见水印>

我们现在来讲一下,首先我们将横坐标离散,之后将离散后的坐标映射到线段树上,之后按照矩形和纵坐标从小到大排序(保证他是从最下往最上扫)当我们遇到下边的时候我们就将线段+1,表示这个时候我们加进来了一条边,遇到上边我们将对应的线段-1,这样之后就会像图中一样,会把矩形分割成为很多的小矩形,之后高度就是我们纵坐标的差,那么小矩形的长呢,我们就是用线段树维护小矩形的长。

上代码把:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define lson l , m , rt<<1
#define rson m+1,r,rt<<1|1
const int maxnN = 220; 
using namespace std;
struct Seg
{
	double l,r,h;
	int f;
	Seg(){}
	Seg(double a,double b,double c,double d):l(a),r(b),h(c),f(d){}
	bool operator < (const Seg &cmp) const 
	{
		return h<cmp.h;
	}
}e[maxnN];
struct node
{
	int cnt;
	double len;
}sum[maxnN<<2];
double X[maxnN];
void pushdown(int l,int r,int rt)
{
	if(sum[rt].cnt)
	{
		sum[rt].len = X[r+1] - X[l];
	}
	else if(l == r)
	{
		sum[rt].len = 0;
	}
	else
	{
		sum[rt].len = sum[rt<<1].len+sum[rt<<1|1].len;
	}
}
void update(int L,int R,int l,int r, int rt,int val)
{
	if(L<=l && R>=r)
	{
		sum[rt].cnt += val;
		pushdown(l,r,rt);
		return ;
	}
	int m = (l+r)>>1;
	if(L<=m)
	{
		update(L,R,lson,val);
	}
	if(R>m)
	{
		update(L,R,rson,val);
	}
	pushdown(l,r,rt);
}
void print(int l,int r,int rt)
{
//	cout<<"---"<<sum[rt].len<<endl;
	if(l == r)
	{
		return ;
	}
	int m = (l+r)>>1;
	print(lson);
	print(rson); 
}
int main()
{
	int n;
	double a,b,c,d;
	int q = 1;
	while(scanf("%d",&n)!=EOF)
	{
		memset(sum,0,sizeof(sum));
		if(n == 0 )break;
		int cnt = 0 ;
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
			X[cnt] = a;
			e[cnt++] =Seg(a,c,b,1);
			X[cnt] = c;
			e[cnt++] = Seg(a,c,d,-1);
		}
		sort(X,X+cnt);
		sort(e,e+cnt);
		int m = unique(X,X+cnt)-X;
		double ans = 0 ;
		for(int i = 0 ; i < cnt; i++)
		{
			int l = lower_bound(X,X+m,e[i].l) - X;
			int r = lower_bound(X,X+m,e[i].r) - X -1;
			update(l,r,0,m,1,e[i].f);
			ans+=(sum[1].len * (e[i+1].h - e[i].h));
		//	cout<<"sum = "<<sum[1].len<<endl;
			print(0,n,1);
		//	puts("-------------------------------");
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",q++,ans);
	}
	return 0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值