覆盖的面积(HDU - 1255)

覆盖的面积(HDU - 1255)

在平面上给出若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
这题相当于扫描线的进阶版本。基本的扫描线就不讲了,讲一下这题的拓展处。记录一下每一段被完全覆盖的次数,维护区间被覆盖的面积(覆盖一次以上)维护区间被覆盖两次以上的部分的面积,显然,对于已经覆盖>=2的情况,整个区域都是合法的情况,更新的时候整段都当做合法的维护进去就好。对于当前整个区间已经被覆盖了一次的情况,那么向下询问子区间内已经覆盖一次以上的区间,那么合起来就是重复两次以上了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=2022;
#define sfi(a) scanf("%d",&a)
#define sfl(a) scanf("%lld",&a)
#define sff(a) scanf("%lf",&a)
struct Line
{
	double x;
	double rupy,rdowny;
	int upy,downy;
	int flag;
	bool operator<(const Line b)const
	{
		return x<b.x;
	}
}line[maxn<<1];
struct Segmentree
{
	int cov=0;
	int l,r;
	double dat1,dat2;
	#define l(p) tre[p].l
	#define r(p) tre[p].r
	#define cov(p) tre[p].cov
	#define dat1(p) tre[p].dat1
	#define dat2(p) tre[p].dat2
}tre[maxn<<3];
LL ix[maxn<<1];int n,m;
double ry[maxn<<1];

void pushup(int p)
{
	if(cov(p))
	{
		dat1(p)=ry[r(p)+1]-ry[l(p)];
		if(cov(p)>=2)
		{
			dat2(p)=ry[r(p)+1]-ry[l(p)];
		}
		else if(cov(p)==1)
		{
			dat2(p)=dat1(p<<1)+dat1(p<<1|1);
		}
	}
	else 
	{
		dat1(p)=dat1(p<<1)+dat1(p<<1|1);
		dat2(p)=dat2(p<<1)+dat2(p<<1|1);
	}
}
void build(int p,int l,int r)
{
	l(p)=l;r(p)=r;
	if(l==r){return;}
	int mid=(l(p)+r(p))/2;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
void addtre(int p,int l,int r,int val)
{
	if(l<=l(p)&&r(p)<=r)
	{
		cov(p)+=val;
		pushup(p);
		return;
	}
	int mid=(l(p)+r(p))/2;
	if(mid>=l)addtre(p<<1,l,r,val);
	if(mid<r)addtre(p<<1|1,l,r,val);
	pushup(p);
}

void solve()
{
	sfi(n);
	memset(tre,0,sizeof(tre));
	for(int i=1;i<=n;++i)
	{
		double fx,fy,sx,sy;
		sff(fx);sff(fy);sff(sx);sff(sy);
		
		line[i].rupy=max(fy,sy);line[i].rdowny=min(fy,sy);
		line[i].x=min(fx,sx);line[i].flag=1;
		
		line[i+n].rupy=max(fy,sy);line[i+n].rdowny=min(fy,sy);
		line[i+n].x=max(fx,sx);line[i+n].flag=-1;
		
		ry[i]=fy;ry[i+n]=sy;
	}
	
	sort(line+1,line+1+2*n);
	sort(ry+1,ry+1+2*n);
	build(1,1,2*n);
	for(int i=1;i<=2*n;++i)
	{
		line[i].upy=lower_bound(ry+1,ry+1+2*n,line[i].rupy)-ry;
		line[i].downy=lower_bound(ry+1,ry+1+2*n,line[i].rdowny)-ry;
	}
	double ans=0.00;
	for(int i=1;i<=2*n;++i)
	{
		if(i!=1)ans+=dat2(1)*(line[i].x-line[i-1].x);
		addtre(1,line[i].downy,line[i].upy-1,line[i].flag);
	}
	printf("%.2lf\n",ans+1e-6);
}
int main()
{
	int _;sfi(_);
	while(_--)solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值