覆盖的面积(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;
}