扫描线算法。这是一棵真.线段树。其实每个叶子节点记录[n,n+1)的信息即可。具体实现参见代码中神奇的-1。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10005
using namespace std;
struct tree
{
int left,right,q;
double sum;
}node[maxn];
struct seg
{
double x1,x2,h;
int flag;
}s[5005];
int n,father[maxn];
double q,w,e,z,hash[10005];
double ans;
bool cmp(seg x,seg y)
{
return x.h<y.h;
}
void build(int i,int left,int right)
{
node[i].left=left;
node[i].right=right;
node[i].sum=0;
node[i].q=0;
if (left==right)
{
father[left]=i;
return;
}
else
{
int mid=(left+right)>>1;
i=i<<1;
build(i,left,mid);
build(i+1,mid+1,right);
}
}
int find(double x)
{
int l,r;
l=1;r=2*n;
for(;;)
{
int mid=(l+r)>>1;
if (hash[mid]==x) return mid;
else if (hash[mid]<x) l=mid+1;
else r=mid-1;
}
}
void pushup(int i)
{
int left=node[i].left,right=node[i].right;
if (node[i].q>0) node[i].sum=hash[right+1]-hash[left];
else if (left==right) node[i].sum=0;
else node[i].sum=node[i<<1].sum+node[i<<1|1].sum;
}
void modify(int i,int l,int r,int flag)
{
int left=node[i].left,right=node[i].right;
if ((l==left) && (r==right))
{
node[i].q=node[i].q+flag;
pushup(i);
return;
}
int mid=(left+right)>>1;
if (r<=mid) modify(i<<1,l,r,flag);
else if (l>=mid+1) modify(i<<1|1,l,r,flag);
else
{
modify(i<<1,l,mid,flag);
modify(i<<1|1,mid+1,r,flag);
}
pushup(i);
}
int main()
{
while (scanf("%d",&n)==1)
{
if (n==0) break;
ans=0;
build(1,1,2*n);
for (int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&q,&w,&e,&z);
s[i*2-1].x1=q;s[i*2-1].x2=e;s[i*2-1].h=w;s[i*2-1].flag=1;
s[i*2].x1=q;s[i*2].x2=e;s[i*2].h=z;s[i*2].flag=-1;
hash[i*2-1]=q;hash[i*2]=e;
}
sort(s+1,s+n*2+1,cmp);
sort(hash+1,hash+n*2+1);
for (int i=1;i<=n*2-1;i++)
{
int ll=find(s[i].x1),rr=find(s[i].x2)-1;
modify(1,ll,rr,s[i].flag);
ans=ans+node[1].sum*(s[i+1].h-s[i].h);
}
printf("%.2lf\n",ans);
}
return 0;
}