解题
求覆盖至少两次的面积。
用sum表示被覆盖至少一次的长度,用ss表示被覆盖至少两次的长度。这题与hdu1542的区别就在于更新ss。
首先像hdu1542那样去更新sum(因为需要用到sum去更新ss)。
根据该区间被完全覆盖的次数来更新ss:
如果add大于1,那么ss等于整个区间。
如果add等于1,那么ss等于左子树的sum值加右子树的sum值。(因为该区间被完全覆盖一次,左子树被覆盖一次累加该区间就至少两次,同理累加右子树)。
如果是叶子结点,ss等于0.
AC代码
//280ms 2.1MB
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define lson p<<1
#define rson p<<1|1
using namespace std;
const int maxn=3e3+100;
struct node
{
int l,r;//线段树所维护的区间
int add;//add为1表示加一次覆盖,为-1表示减一次覆盖
double sum,ss;//对应的被覆盖y一次的长度、两次的长度
}T[maxn<<2];
struct line///从下到上扫描
{
double h,L,R;//高度和左右端点
int mark;//标记为1表示下边,为-1表示上边
bool operator<(const line &o)const
{
return h<o.h;
}
}li[maxn];
double pos[maxn];
void up(int p)
{
//更新被覆盖至少一次的长度
if(T[p].add) T[p].sum=pos[T[p].r-1]-pos[T[p].l-1];
else if(T[p].l==T[p].r) T[p].sum=0;
else T[p].sum=T[lson].sum+T[rson].sum;
//更新被覆盖至少两次的长度
if(T[p].add>1) T[p].ss=pos[T[p].r-1]-pos[T[p].l-1];//长度是对应在pos数组中的值的差
//不是线段树所维护的区间长度
else if(T[p].l==T[p].r) T[p].ss=0;//不全部覆盖且是叶子结点,一定没有被覆盖的部分
else if(T[p].add==1) T[p].ss=T[lson].sum+T[rson].sum;
else if(T[p].add==0) T[p].ss=T[lson].ss+T[rson].ss;
}
void build(int p,int l,int r)
{
T[p].add=0;T[p].sum=0;T[p].ss=0;
T[p].l=l,T[p].r=r;
if(l+1==r) return ;///注意叶子结点是一个长度为1的线段
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid,r);///注意是mid,不是mid+1
}
void update(int p,int x,int y,int c)
{
if(T[p].l==x && T[p].r==y)
{
T[p].add+=c;
up(p);
return ;
}
int mid=(T[p].l+T[p].r)>>1;
if(y<=mid) update(lson,x,y,c);
else if(x>=mid) update(rson,x,y,c);///注意是>=mid,不是>mid
else
{
update(lson,x,mid,c);
update(rson,mid,y,c);///注意是mid,不是mid+1
}
up(p);
}
int main()
{
int n,kase=0;
scanf("%d",&kase);
while(kase--)
{
scanf("%d",&n);
int cnt=0,d=0;
for(int i=0; i<n; i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
pos[d++]=x1;
pos[d++]=x2;
li[cnt].h=y1;
li[cnt].L=x1;
li[cnt].mark=1;
li[cnt++].R=x2;
li[cnt].h=y2;
li[cnt].L=x1;
li[cnt].mark=-1;
li[cnt++].R=x2;
}
sort(li,li+cnt);
sort(pos,pos+d);
int m=unique(pos,pos+d)-pos;
build(1,1,m);
double ans=0;
for(int i=0; i<cnt; i++)
{
int l=lower_bound(pos,pos+m,li[i].L)-pos+1;
int r=lower_bound(pos,pos+m,li[i].R)-pos+1;
ans+=i==0?0:(li[i].h-li[i-1].h)*T[1].ss;
update(1,l,r,li[i].mark);
}
printf("%.2lf\n",ans);
}
return 0;
}