HDU 1542 Atlantis

本人太菜,注释写得有点多,都是自己错了的地方~~~以后一定好好记住

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

#define lson l , m , th << 1
#define rson m + 1 , r , th << 1 | 1
#define MAX 500

using namespace std;
//题目核心思想是把一个正方形看成两条边,再以每条边的高度进行排序,然后再一次往上扫描。
//所以这一类题目又叫线段扫描 
struct line{
	double l,r,h;
	int flag;//如果flag=1,则为上边;如果flag=-1,则为下边
	
	line (){}
	line(double a,double b,double c,int d) : l(a) , r(b) , h(c) , flag(d) {}
	bool operator < (const line &cmp) const {
		return h < cmp.h;
	}
}ll[MAX];
int cover[MAX*4];
double sum[MAX*4];
double X[MAX];//用于离散化,通过Bin()这个函数实现离散化 
int Bin(double key,int n,double X[]){
	int l=0,r=n-1;
	while(l<=r){
		int m=(l+r)/2;
		if(X[m]<key) l=m+1;
		if(X[m]>key) r=m-1;//这儿的-1很重要,记住! 
		if(X[m]==key) return m;
	}
	return -1;
}
void PushUp(int th,int l,int r){
	//if(l==r) sum[th]=0;
	//else if(cover[th]) sum[th]=X[r+1]-X[l];
	//理解线段树的性质,写成这样可以说完全没懂什么叫线段树!! 
	//printf("l:%d r:%d %d th:%d\n",l,r,cover[th],th);
	if(cover[th]) sum[th]=X[r+1]-X[l];
	else if(l==r) sum[th]=0;//经常都需要特判叶子节点,因为它很特殊 
	else sum[th]=sum[th*2]+sum[th*2+1]; 
}
void UpDate(int L,int R,int v,int l,int r,int th){
	if(L<=l&&r<=R){
		cover[th]+=v;
		//这儿是整个想法的核心,把上边标记成1,下边标记成-1,
	 	//在累加过后直接乘以h,就可以算出面积 
		PushUp(th,l,r);
		return ;//记住return 
	}
	int m=(l+r)/2;
	if(m >= L) UpDate(L,R,v,lson);
	if(m < R) UpDate(L,R,v,rson);
	PushUp(th,l,r);
}
int main(){
	int n,m,cas=1;
	double x1,y1,x2,y2;
	int i,j,k;
	while(scanf("%d",&n)!=EOF){
		memset(cover,0,sizeof(cover));
		memset(sum,0,sizeof(sum));
		
		if(n==0) break;
		m=0;
		while(n--){
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);	
			X[m]=x1;
			ll[m++]=line(x1,x2,y1,1);
			X[m]=x2;
			ll[m++]=line(x1,x2,y2,-1);
		}
		sort(X,X+m);
		sort(ll,ll+m);

		//二分前需要先把这个数组处理一下
		for(i=1,k=1;i<m;i++){
			if(X[i]!=X[i-1]) X[k++]=X[i]; //这样子X[0]还是X[0],写的很精辟
		}
		
		double ans=0;//每个值一定要赋初值 
		for(i=0;i<m-1;i++){
			int l=Bin(ll[i].l,k,X);
			int r=Bin(ll[i].r,k,X)-1;//为什么要减1呢???这儿对于这个问题一直还有疑问,希望有大牛来解答
			//printf("l:%d r:%d  ll:%lf rr:%lf\n",l,r,ll[i].l,ll[i].r);
			//if(l!=r) UpDate(l,r,0,k-1,1);错!
			//if(l<=r) {
			///	UpDate(l,r,ll[i].flag,0,k-1,1); 
			//	ans+=(ll[i+1].h-ll[i].h)*sum[1];
			//}
			if(l<=r) 
				UpDate(l,r,ll[i].flag,0,k-1,1); 
			//printf("%lf\n\n",sum[1]);
			ans+=(ll[i+1].h-ll[i].h)*sum[1];
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",cas++ , ans);
	}
			
}
 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值