【HDU 1542】Atlantis(线段树+离散化,矩形面积并)

求矩形面积并,离散化加线段树。

扫描线法:

用平行x轴的直线扫,每次ans+=(下一个高度-当前高度)*当前覆盖的宽度。

#include<algorithm>
#include<cstdio>
#include<cstring>
#define dd double
#define ll long long
#define N 201
using namespace std;
struct P{dd s,e,h;int f;}p[N];
struct Tree{dd sum;int c;}t[N<<5];
dd a,b,c,d,x[N],ans;
int n,m,num;
int cmp(const P &a,const P &b){
	return a.h<b.h;
}
void pushUp(ll rt,ll l,ll r){
	if(t[rt].c)t[rt].sum=x[r+1]-x[l];//r+1是因为节点[l,r]表示区间[x[l],x[r+1]]。
	else if(l==r)t[rt].sum=0;
	else t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
}
void update(ll s,ll e,ll rt,ll l,ll r,ll v){
	if(s<=l&&r<=e) t[rt].c+=v;
	else {
		if(l>e||r<s)return;
		ll m=l+r>>1;
		update(s,e,rt<<1,l,m,v);
		update(s,e,rt<<1|1,m+1,r,v);
	}
	pushUp(rt,l,r);
}
int main()
{
	while(scanf("%d",&n),n){
		int k=0;
		for(int i=0;i<n;i++){
			scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
			x[++k]=a,p[k]=(P){a,c,b,1};
			x[++k]=c,p[k]=(P){a,c,d,-1};
		}
		sort(x+1,x+1+k);
		sort(p+1,p+1+k,cmp);
		m=1;
		for(int i=1;i<=k;i++)
			if(x[i]!=x[i-1])x[m++]=x[i];
		ans=0;
		for(int i=1;i<=k;i++){//共k条线段,每次计算p[i].h到p[i+1].h之间的面积,第k次相当于清空所有,酱就不用初始化线段树了。
			int l=lower_bound(x,x+m,p[i].s)-x;
			int r=lower_bound(x,x+m,p[i].e)-x-1;//r-1同上原因
			update(l,r,1,0,m-1,p[i].f);
			ans+=t[1].sum*(p[i+1].h-p[i].h);
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",++num,ans);
	}
	return 0;
}

另一种方法还是线段树,这里扫描线用的是平行y轴的直线,每次增加的面积是当前扫描的竖线所在的高度区间的最后一次的x与当前x的差值乘上区间的高度。所以每次增加的不一定是一个矩形,而是多个矩形并。

 

#include<cstdio>
#include<algorithm>
#define dd double
using namespace std;
#define N 201
struct P{dd x,y1,y2;int f;}p[N];
struct TREE{dd y1,y2,x;int c,f;}tree[N<<5];
dd x1,y1,x2,y2,y[N];
int n,k,num;
int cmp(const P &a,const P &b){
	return a.x<b.x;
}
void build(int i,int l,int r){
	tree[i].c=tree[i].f=0;
	tree[i].y1=y[l];//直接将线段树节点代表的区间存在线段树里
	tree[i].y2=y[r];
	if(l+1==r){
		tree[i].f=1;
		return;
	}
	int mk=(l+r)>>1;
	build(i<<1,l,mk);
	build(i<<1|1,mk,r);
}
dd insert(int i,dd x,dd l,dd r,int flag){
	if(r<=tree[i].y1||l>=tree[i].y2)
		return 0;
	if(tree[i].f){//离散后的一个最小区间,叶子节点
		dd ans;
		if(tree[i].c>0)//全覆盖
			ans=(x-tree[i].x)*(tree[i].y2-tree[i].y1);//(当前x-该区间最后的x)*区间高度
		else
			ans=0;
		tree[i].x=x;//该区间最新的x
		tree[i].c+=flag;//更新覆盖
		return ans;
	}
	return insert(i<<1,x,l,r,flag)+insert(i<<1|1,x,l,r,flag);
}
int main(){
	while(scanf("%d",&n),n){
		k=0;
		for(int i=1;i<=n;i++){
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			y[++k]=y1,p[k]=(P){x1,y1,y2,1};
			y[++k]=y2,p[k]=(P){x2,y1,y2,-1};
		}
		sort(y+1,y+k+1);
		sort(p+1,p+k+1,cmp);
		//没有去重,其实数量少,没必要。
		build(1,1,k);
		dd ans=0;
		for(int i=1;i<=k;i++)
			ans+=insert(1,p[i].x,p[i].y1,p[i].y2,p[i].f);
		printf("Test case #%d\nTotal explored area: %.2f\n\n",++num,ans);
	}
	return 0;
}

  

时间: 2024-12-21 17:42:49

【HDU 1542】Atlantis(线段树+离散化,矩形面积并)的相关文章

POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线段树维护两个值:cover和len,cover表示该线段区间目前被覆盖的线段数目,len表示当前已覆盖的线段长度(化为离散前的真值),每次加入一条线段,将其y_low,y_high之间的区间染上line[i].cover,再以tree[1].len乘以接下来的线段的x坐标减去当前x坐标,即计算了一部

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

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

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

hdu 1542 Atlantis(线段树)

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

POJ&#183;1151 Atlantis&#183;线段树求矩形面积并

题目在这:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Description 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 is

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

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc

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

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

HDU 1542 Atlantics 线段树+离散化扫描

将 x 轴上的点进行离散化,扫描线沿着 y 轴向上扫描 每次添加一条边不断找到当前状态有效边的长度 , 根据这个长度和下一条边形成的高度差得到一块合法的矩形的面积 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 8 const int MAX=200+10; 9 int flag[MAX&l