在线段树中定义一个cover域,表示该线段区间目前被覆盖的线段数目。另外再加一个len域,表示该区间可用于与下一线段求并面积的y坐标区间长度。然后利用简单的dp,将所有信息集中于tree[1].len上
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3000;
int n,m;
double X[maxn];
struct seg
{
double h,l,r;
int c;
seg(double a,double c,double b,int p):l(a),r(c),h(b),c(p){}
bool operator <(const seg &a)const
{
return h<a.h;
}
seg(){}
}s[maxn];
struct IntervalTree
{
double sum[maxn<<2];
int cnt[maxn<<2];
void init(){memset(sum,0,sizeof(sum));memset(cnt,0,sizeof(cnt));}
void PushUp(int o,int l,int r)
{
if(cnt[o])sum[o]=X[r+1]-X[l];
else if(l==r)sum[o]=0;
else sum[o]=sum[o*2]+sum[o*2+1];
}
void update(int q1,int q2,int o,int l,int r,int flag)
{
if(q1<=l&&r<=q2)
{
cnt[o]+=flag;
PushUp(o,l,r);
return;
}
int m=(l+r)/2;
if(q1<=m)update(q1,q2,o*2,l,m,flag);
if(q2>m)update(q1,q2,o*2+1,m+1,r,flag);
PushUp(o,l,r);
}
};
int binary_search(double x,int R)
{
int l=0,r=R-1,mid;
while(l<=r)
{
mid=(l+r)/2;
if(X[mid]==x)return mid;
if(X[mid]>=x)r=mid-1;
else l=mid+1;
}
return -1;
}
int main()
{
//freopen("in.txt","r",stdin);
double a,b,c,d;
int cas=1;
while(scanf("%d",&n)!=EOF&&n)
{
m=0;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
X[m]=a;
s[m++]=seg(a,c,b,1);
X[m]=c;
s[m++]=seg(a,c,d,-1);
}
sort(X,X+m);
sort(s,s+m);
int num=1;
for(int i=1;i<m;i++)
if(X[i]!=X[i-1])X[num++]=X[i];
IntervalTree tree;
tree.init();
double ans=0;
for(int i=0;i<m-1;i++)
{
int l=binary_search(s[i].l,num);
int r=binary_search(s[i].r,num)-1;
if(l<=r)tree.update(l,r,1,0,num-1,s[i].c);
ans+=tree.sum[1]*(s[i+1].h-s[i].h);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",cas++,ans);
}
return 0;
}