题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
题意:
给出N(N<=1000)个矩形,求至少被两个矩形的所覆盖的面积和。
思路:
和上篇博客 链接 求多个矩形面积交的思路很相像,那个是维护当前有效宽求面积并,这里只需将cnt[i]>=2的看做有效宽(因为cnt记录的是扫描线的覆盖情况,当某个区间被下底边至少覆盖了两次,那么这条边以上的面积是由至少两个以上的矩形交和而成)所以唯一的区别在于更新len(区间有效长度)时看cnt的情况。
代码:
#include<bits/stdc++.h>
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
#define N 2005
using namespace std;
int cnt[N<<2];
double len[N<<2];
double X[N<<1];
struct edge
{
double l,r,h;
int f;
edge() {}
edge(double l,double r,double h,int f):l(l),r(r),h(h),f(f) {}
bool operator < (const edge &b) const
{
return h<b.h;
}
} e[N<<1];
void push_up(int o)
{
if(cnt[o<<1]==-1 || cnt[o<<1|1]==-1)
cnt[o]=-1;
else if(cnt[o<<1]!=cnt[o<<1|1])
cnt[o]=-1;
else
cnt[o]=cnt[o<<1];
len[o]=len[o<<1]+len[o<<1|1];
}
void push_down(int o,int l,int r)
{
if(cnt[o]!=-1)
{
int mid=l+r>>1;
cnt[o<<1]=cnt[o<<1|1]=cnt[o];
len[o<<1]=(cnt[o]>=2 ? X[mid+1]-X[l] :0);
len[o<<1|1]=(cnt[o]>=2 ? X[r+1]-X[mid+1] :0);
}
}
void build(int l,int r,int o)
{
if(l==r)
{
cnt[o]=0;
len[o]=0.0;
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
push_up(o);
}
void update(int L,int R,int v,int l,int r,int o)
{
if(L<=l&&r<=R)
{
if(cnt[o]!=-1)
{
cnt[o]+=v;
len[o]=(cnt[o]>=2 ? X[r+1]-X[l]:0);
return;
}
}
push_down(o,l,r);
int mid=l+r>>1;
if(L<=mid)
update(L,R,v,lson);
if(R>mid)
update(L,R,v,rson);
push_up(o);
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
double x1,y1,x2,y2;
for(int i=1; i<=n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
X[i]=x1,X[i+n]=x2;
e[i]=edge(x1,x2,y1,1);
e[i+n]=edge(x1,x2,y2,-1);
}
sort(e+1,e+1+2*n);
int m=unique(X+1,X+1+2*n)-X-1;
sort(X+1,X+1+m);
build(1,m-1,1); //m个不同的点分成m-1个区间
double ans=0.0;
for(int i=1; i<=2*n-1; i++)
{
int l=lower_bound(X+1,X+1+m,e[i].l)-X;
int r=lower_bound(X+1,X+1+m,e[i].r)-X-1;
//printf("%d %d\n",l,r);
update(l,r,e[i].f,1,m-1,1);
//printf("%f %f\n",len[1],e[i+1].h-e[i].h);
ans+=len[1]*(e[i+1].h-e[i].h);
}
printf("%.2lf\n",ans);
}
return 0;
}