您的位置:首页 > 其它

Hdu 1542 Atlantis + Hdu 1255 覆盖的面积 (线段树矩形面积并)

2013-05-25 15:18 411 查看
用线段树解决矩形面积并的问题。

从以下链接学习,并参考了代码:http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html

目前只能写出朴素写法,dp写法还没有学会。

Hdu 1542

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N=110;

struct LINE
{
	int flag;   //1表示左边,-1表示右边
	double x,y_down,y_up;

	void Get (int _flag,double _x,double _y_down,double _y_up)
	{
		flag=_flag;
		x=_x;
		y_down=_y_down;
		y_up=_y_up;	
	}
	
	bool operator < (const LINE &a) const
	{
		return  x<a.x;
	}
}line[2*N];

struct TREE
{
	double  y_down, y_up;
	double  x;
	int     cover; //用以表示加进线段树中的线段次数
	bool    flag; //flag==true表示达到了叶子节点
}tree[1000*N];
 
int n;
double x1,y1,x2,y2;
double y[2*N];

void Build (int t,int left,int right)
{
	tree[t].x = -1; //-1表示该区间已经没有线段
	tree[t].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则--
	tree[t].y_down = y[left];
	tree[t].y_up = y[right];
	tree[t].flag = false;
	if (left+1==right)
	{
		tree[t].flag=true;
		return;
	}
	int mid=(left+right)>>1;
	Build(2*t,left,mid);
	Build(2*t+1,mid,right);
}

double Insert (int t,double x,double left,double right,int flag) //flag表示为左边还是右边
{
	if (right<=tree[t].y_down || left>=tree[t].y_up) 
		return 0;
	if (tree[t].flag) 
		if (tree[t].cover > 0) //递归到了叶子节点
		{
			double temp_x=tree[t].x;
			double ans=(x-temp_x)*(tree[t].y_up - tree[t].y_down);
			tree[t].x=x;   //定位上一次的x
			tree[t].cover+=flag;
			return ans;
		}
		else 
		{
			tree[t].cover += flag;
			tree[t].x = x;
			return 0;
		}
	
	double ans1, ans2;
	ans1 = Insert(2*t, x, left, right, flag);
	ans2 = Insert(2*t+1, x, left, right, flag);
	return ans1+ans2;
}
 
int main ()
{
#ifdef ONLINE_JUDGE
#else
	freopen("read.txt","r",stdin);
#endif
	int Cas=0,i;
	while (scanf("%d",&n),n)
	{
		int id=1;
		for (i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			y[id]=y1;
			line[id++].Get(1,x1,y1,y2);
			y[id]=y2;
			line[id++].Get(-1,x2,y1,y2);
		}
		sort (y+1,y+id);//把所有的纵坐标按从小到大排序
		sort (line+1,line+id);
		Build (1,1,id-1);
		double ans=0;
		for (i=1;i<id;i++)
			ans += Insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag);
		printf("Test case #%d\nTotal explored area: %.2f\n\n",++Cas,ans);
	}
	return 0;
}


Hdu 1255

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N=1005;

struct LINE
{
	int flag;   //1表示左边,-1表示右边
	double x,y_down,y_up;

	void Get (int _flag,double _x,double _y_down,double _y_up)
	{
		flag=_flag;
		x=_x;
		y_down=_y_down;
		y_up=_y_up;	
	}
	
	bool operator < (const LINE &a) const
	{
		return  x<a.x;
	}
}line[2*N];

struct TREE
{
	double  y_down, y_up;
	double  x;
	int     cover; //用以表示加进线段树中的线段次数
	bool    flag; //flag==true表示达到了叶子节点
}tree[1001*N];
 
int n;
double x1,y1,x2,y2;
double y[2*N];

void Build (int t,int left,int right)
{
	tree[t].x = -1; //-1表示该区间已经没有线段
	tree[t].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则--
	tree[t].y_down = y[left];
	tree[t].y_up = y[right];
	tree[t].flag = false;
	if (left+1==right)
	{
		tree[t].flag=true;
		return;
	}
	int mid=(left+right)>>1;
	Build(2*t,left,mid);
	Build(2*t+1,mid,right);
}

double Insert (int t,double x,double left,double right,int flag) //flag表示为左边还是右边
{
	if (right<=tree[t].y_down || left>=tree[t].y_up) 
		return 0;
	if (tree[t].flag) 
		if (tree[t].cover > 1)    //覆盖2次或以上
		{
			double temp_x=tree[t].x;
			double ans=(x-temp_x)*(tree[t].y_up - tree[t].y_down);
			tree[t].x=x;   //定位上一次的x
			tree[t].cover+=flag;
			return ans;
		}
		else 
		{
			tree[t].cover += flag;
			tree[t].x = x;
			return 0;
		}
	
	double ans1, ans2;
	ans1 = Insert(2*t, x, left, right, flag);
	ans2 = Insert(2*t+1, x, left, right, flag);
	return ans1+ans2;
}
 
int main ()
{
#ifdef ONLINE_JUDGE
#else
	freopen("read.txt","r",stdin);
#endif
	int T;
	scanf("%d",&T);
	while (T--)
	{
		int id=1,i;
		scanf("%d",&n);
		for (i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			y[id]=y1;
			line[id++].Get(1,x1,y1,y2);
			y[id]=y2;
			line[id++].Get(-1,x2,y1,y2);
		}
		sort (y+1,y+id);//把所有的纵坐标按从小到大排序
		sort (line+1,line+id);
		Build (1,1,id-1);
		double ans=0;
		for (i=1;i<id;i++)
			ans += Insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag);
		printf("%.2lf\n",ans);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: