hdu 1542 扫描线+离散化

Problem - 1542 (hdu.edu.cn)

我用【l,r】来表示【l,r+1】这个区间,保证所有的区间都不会漏,可以自己尝试着画出线段树,就好理解了。

于是,只需要维护线段树的【1,len-1】这个区间即可维护整个区间(len为离散化之后的长度)

从左到右扫描,将每一条离散化后的竖边用结构体打包保存,包括了(x,y1,y2,flag),flag是1表示是矩形左边的竖边,-1表示右边的。

排序后,从左到右遍历竖边(最后一条竖边不用遍历),对于遍历的每条竖边,先将其对于的y轴的【y1,y2】区间加1或者减1,表示对于区间+1或者-1,然后累加每条竖边和他的下一条竖边夹着的矩形的面积即可,最后一条竖边没有下一条竖边了,于是不用遍历最后一条竖边

#include<bits/stdc++.h>

#define ls id<<1
#define rs id<<1|1
#define mid (l+r>>1)

using namespace std;

const int maxn = 1e2+7;

int n,len;
double x[maxn<<1],xx[maxn<<1];
int len_x;
double y[maxn<<1],yy[maxn<<1];
int len_y;

struct tt{
	int x,y1,y2,flag;
}p[maxn<<1]; 


bool cmp(tt p1,tt p2){
	return p1.x<p2.x;
}

void init(){
	for(int i=1;i<=n;i++){
		double x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		int l=(i<<1)-1,r=i<<1;
		x[l]=xx[l]=x1,x[r]=xx[r]=x2;
		y[l]=yy[l]=y1,y[r]=yy[r]=y2;
	}
	sort(x+1,x+1+len);
	sort(y+1,y+1+len);
	len_x=unique(x+1,x+1+len)-x-1;
	len_y=unique(y+1,y+1+len)-y-1;
	for(int i=1;i<=n;i++){
		int l=(i<<1)-1,r=i<<1;
		int px1=lower_bound(x+1,x+1+len_x,xx[l])-x;
		int py1=lower_bound(y+1,y+1+len_y,yy[l])-y;
		int px2=lower_bound(x+1,x+1+len_x,xx[r])-x;
		int py2=lower_bound(y+1,y+1+len_y,yy[r])-y;
		p[l]={px1,py1,py2,1};
		p[r]={px2,py1,py2,-1};
	}
	sort(p+1,p+1+len,cmp);
}

int tree[maxn<<3];
double num[maxn<<3];
int lazy[maxn<<3];

void build(int l,int r,int id){
	if(l==r){
        tree[id]=0;
		num[id]=y[l+1]-y[l];
		return;
	}
	build(l,mid,ls);
	build(mid+1,r,rs);
	num[id]=num[ls]+num[rs];
    tree[id]=0;
}

void up(int id){
	tree[id]=min(tree[ls],tree[rs]);
	if(tree[ls]==tree[rs])num[id]=num[ls]+num[rs];
	else if(tree[ls]<tree[rs])num[id]=num[ls];
	else num[id]=num[rs];
}

void down(int id){
	lazy[ls]+=lazy[id];
	lazy[rs]+=lazy[id];
	tree[ls]+=lazy[id];
	tree[rs]+=lazy[id];
	lazy[id]=0;
}

void update(int l,int r,int id,int x,int y,int val){
	if(x<=l&&r<=y){
		tree[id]+=val;
		lazy[id]+=val;
		return;
	}
	if(lazy[id]){
		if(l==r)lazy[id]=0;
		else down(id);
	}
	if(x<=mid)update(l,mid,ls,x,y,val);
	if(y>mid)update(mid+1,r,rs,x,y,val);
	up(id);
}

int main(void){
	int cnt=0;
    int f=0;
	while(cin>>n&&n){
		
		len=n<<1;
		
		init();//离散化数据 
		
		build(1,len_y-1,1);//初始化线段树 
		
		memset(lazy,0,sizeof(lazy));//别忘记初始化lazy数组 不然多个样例可能会wa 
		
		double ans=0;
		
		for(int i=1;i<len;i++){
			//每次更新一条竖边,对应y轴的区间[p[i].y1,p[i].y2-1]加上flag(左边为1,右边为-1),表示被覆盖或者取消覆盖 
			update(1,len_y-1,1,p[i].y1,p[i].y2-1,p[i].flag);
			//矩形面积计算:底 ×高 
			ans+=(x[p[i+1].x]-x[p[i].x])*((y[len_y]-y[1])-(tree[1]?0:num[1]));
		}
		
		printf("Test case #%d\n",++cnt);
		printf("Total explored area: %.2lf\n\n",ans);
	}
	/*
	Test case #1
    Total explored area: 180.00 
	*/
	
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值