HDU1542 Atlantis 扫描线求矩形面积并 模板题

6 篇文章 0 订阅
2 篇文章 0 订阅

题意:给你平面内一些矩形的位置和大小,让你求面积之并(能看到的面积之和)。
思路:扫描线板子题,自己最开始看了看扫描线实现的思路自己莽着写了一个竟然过了,但是后来证明是这个题数据量小,但是数据量一大就会T掉。。。
所以老老实实又重新学了一遍扫描线。其实就是updata函数写的不对,总体思路还是离散化、建树、求面积。
要注意这里有一个小难点就是点和区间的对应。值得仔细琢磨一下。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define maxn 2003
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,cnt,size,casee=0;///cnt为总边数 size为去重后y长度
double y[maxn];///y里面放去重排序后的y 然后可从里面查找离散化后对应整数(下标
struct Side{
    double x,y1,y2;///y2>y1
    int k;
}side[maxn];
struct node{
    int l,r,c;///c来记录次数 是否有!
    double sum;
}t[maxn<<1];//因为本来就是乘以二
void init(){
    cnt=0;
    cl(y,0);
    cl(side,0);
    cl(t,0);
}
bool cmp(Side a,Side b){///扫描顺序排序
    return a.x<b.x;
}
void pushup(int k){
	if(t[k].c){//若该段被覆盖了 
		t[k].sum=y[t[k].r+1]-y[t[k].l];//注意这里的实际长度计算法
	}else{//若该段没有被覆盖
		if(t[k].l==t[k].r){//若是叶结点 即 只有一小段间隔 
			t[k].sum=0; 
		}else{
			t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
		}
	}
}
void build(int k,int l,int r){
	t[k].l=l,t[k].r=r;
	if(l==r){
		t[k].c=t[k].sum=0;
	}else{
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		//t[k].c=t[k].sum=0;
		pushup(k);
	}
}
void updata(int k,int l,int r,int v){
	if(l<=t[k].l&&t[k].r<=r){//若到了目的区间! 
		t[k].c+=v;
		pushup(k); 
	}else{
		int mid=(t[k].l+t[k].r)>>1;
		if(l<=mid) updata(k<<1,l,r,v);
		if(mid<r) updata(k<<1|1,l,r,v);
		pushup(k);
	}
}
void input(){
    init();///初始化
    for(int i=1;i<=n;i++){///输入所有点边信息
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);//输入顺序刚开始有问题!!! 
        cnt++;
        y[cnt]=y1;
        side[cnt].x=x1,side[cnt].y1=y1,side[cnt].y2=y2,side[cnt].k=1;
        cnt++;
        y[cnt]=y2;
        side[cnt].x=x2,side[cnt].y1=y1,side[cnt].y2=y2,side[cnt].k=-1;
    }
}
void lsh(){
    sort(y+1,y+cnt+1);
    size=unique(y+1,y+cnt+1)-(y+1);//这里别再int了。。。 
    sort(side+1,side+cnt+1,cmp);///把边按顺序排序
}
int id(double yy){
	return lower_bound(y+1,y+cnt+1,yy)-y;
}
void calculate(){///计算面积
	build(1,1,size-1);
	double ans=0;
	for(int i=1;i<=n*2-1;i++){//对于所有的x(除最后一条边  这里转化好好想想
		updata(1,id(side[i].y1),id(side[i].y2)-1,side[i].k);
		ans+=(t[1].sum*(side[i+1].x-side[i].x));//不需要query!!! 
	}
	printf("Test case #%d\nTotal explored area: %.2lf\n\n",++casee,ans);
}
int main(){
    while(scanf("%d",&n)!=EOF){
    	if(n==0) break;
    	input();///输入各个对角点的信息
    	lsh();///把y离散化  把各个对角点按x排序
    	calculate();///计算面积
	}
    return 0;
}

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 island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

The input file is terminated by a line containing a single 0. Don’t process it.
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值