zoj 1128 || poj 1151 Atlantis(线段树求矩形面积并)

211 篇文章 0 订阅

纠结了好久了,终于差不多弄懂了,无语啊。以后会更难的,线段树水题都刷差不多了都。

求矩形面积并啊。= =。。。

先把Y坐标离散化,然后用扫描线扫描。进入的结构体标记为1,出去的为-1。所以,当一个节点进入又出去之后(也就是标记为0的时候),这一段线段就又可以用啦。

看网上代码直接存的是 y 坐标,这个不是太好理解,因为往常线段树都是存的下标,后来改了改,更直观点吧。

说的有点模糊,自己研究下代码就好了,网上没啥太好的资料。


#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <algorithm>
#define MID(x,y) ((x+y)>>1)
#define L(x) (x<<1)
#define R(x) (x<<1|1)

using namespace std;

const int MAX = 205;
const double eps = 1e-6;
struct rectangle{ double lx,ly,rx,ry;};
struct RRR{double x,y1,y2;int flag;};
struct Tnode{int l,r,cover; double length;};
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
Tnode node[MAX*4]; 
RRR rr[MAX];
double y[MAX];
void init()
{
	memset(node,0,sizeof(node));
}
bool cmp(RRR a,RRR b)
{
	return a.x < b.x;
}
void Build(int t,int l,int r)
{
	node[t].l = l;
	node[t].r = r;
	if( l == r - 1 ) return ;
	int mid = MID(l,r);
	Build(R(t),mid,r);
	Build(L(t),l,mid);
}
void len(int t)
{
	if( node[t].cover > 0 )
		node[t].length = y[node[t].r] - y[node[t].l];
	else
		if( node[t].l == node[t].r - 1 )
			node[t].length = 0.0;
		else
			node[t].length = node[R(t)].length + node[L(t)].length;
}
void Updata(int t,RRR p)
{
	if( y[node[t].l] == p.y1 && y[node[t].r] == p.y2 )
	{
		node[t].cover += p.flag;
		len(t);
		return ;
	}
	int mid = MID(node[t].l,node[t].r);
	if( dyd(p.y1,y[mid]) )
		Updata(R(t),p);
	else
		if( xyd(p.y2,y[mid]) )
			Updata(L(t),p);
		else
		{
			RRR tmp = p;
			tmp.y2 = y[mid];
			Updata(L(t),tmp);
			tmp = p;
			tmp.y1 = y[mid];
			Updata(R(t),tmp);
		}
	len(t);
}

double solve(int n,int cnt)
{
	init();
	Build(1,0,cnt-1);
	double sum = 0.0;
	Updata(1,rr[0]);
	for(int i=1; i<n; i++)
	{
		sum += (rr[i].x - rr[i-1].x)*node[1].length;
		Updata(1,rr[i]);
	}
	return sum;
}
int main()
{
	int n;
	int ind = 1;
	double x1,x2,y1,y2; 
	while( ~scanf("%d",&n) && n )
	{
		int k = 0;
		for(int i=0; i<n; i++)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			rr[k].x = x1; rr[k].y1 = y1;
			rr[k].y2 = y2; rr[k].flag = 1;
			y[k++] = y1;
			rr[k].x = x2; rr[k].y1 = y1;
			rr[k].y2 = y2; rr[k].flag = -1;
			y[k++] = y2;
		}
		sort(rr,rr+k,cmp);
		sort(y,y+k);
		int t = k;				// 去重后,两个 上限是不一样的啊啊啊啊啊  
		k = unique(y,y+k) - y;
		double area = solve(t,k);
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",ind++,area);
	}
return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值