题目
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define _rep(i,a,b) for(int i=(a);i<=(b);i++)
#define _for(i,a,b) for(int i=(a);i<(b);i++)
#define lc o<<1
#define rc o<<1|1
const int N=1e3+10;
int n,num,ca;
struct node{
int dat;
double len;
}tr[N<<2];
struct Edge{
double l,r,h;
int f;//f=-1为上边 1为下边
Edge(){}
Edge(double _l,double _r,double _h,int _f):l(_l),r(_r),h(_h),f(_f){}
bool operator <(const Edge&rhs)const{
return h<rhs.h;}
}edge[N<<1];
double x[N<<1];//给每条边的左端点排序
void push_down(int o,int l,int r)
{
if(tr[o].dat)tr[o].len=x[r+1]-x[l];//当前的边被标记,就把当前的长度加上
else if(l==r)tr[o].len=0;//当为一个点时长度为零
else tr[o].len=tr[lc].len+tr[rc].len;//其他情况把左右两个区间的值加上
}
void update(int o,int l,int r,int nl,int nr,int val)
{
if(nl<=l&&r<=nr)
{
tr[o].dat+=val;
push_down(o,l,r);
return;
}
int mid=(l+r)>>1;
if(nl<=mid)update(lc,l,mid,nl,nr,val);
if(nr>mid)update(rc,mid+1,r,nl,nr,val);
push_down(o,l,r);
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)&&n)
{
memset(tr,0,sizeof(tr));
double a,b,c,d;
num=0;
_for(i,0,n)
{
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
x[num]=a;
edge[num++]=Edge(a,c,b,1);
x[num]=c;
edge[num++]=Edge(a,c,d,-1);
}
sort(x,x+num);sort(edge,edge+num);
int m=unique(x,x+num)-x;
double ans=0;
_for(i,0,num)
{
int l=lower_bound(x,x+m,edge[i].l)-x;//找出离散化以后的值
int r=lower_bound(x,x+m,edge[i].r)-x-1;
update(1,0,m,l,r,edge[i].f);
ans+=tr[1].len*(edge[i+1].h-edge[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++ca,ans);
}
return 0;
}
总结
线段树可以用来维护线段的变化,扫描线算法是常见应用。这题因为范围较大需要离散化。