题目链接:哆啦A梦传送门
题意:给n个矩形,求它们的总面积,覆盖的只算一次。每个矩形给出左下点和右上点。
扫描线从下往上扫描,每次求出该扫描线的有效长度,再与两条线之间的高度相乘就是最后的面积。
线段树更新,遇到该边为矩形的下边就加进去,遇到该边为矩形的上边就减掉。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1000;
struct node{
double l,r,h; ///每条线的左右x端点,该线的纵坐标
int d; ///d=1为下边,d=-1为上边
}a[N];
bool cmp(node X,node Y)
{
return X.h<Y.h;
}
///存储横坐标,离散化使用
double x[N];
struct Node{
int tl,tr;
int s;///该节点被是否被完全覆盖,s不为0即为完全覆盖
double len; ///该节点的有效长度
}tree[N];
void build(int root,int l,int r)
{
tree[root].tl=l;
tree[root].tr=r;
tree[root].len=tree[root].s=0;
if(l==r) return ;
else{
int mid=(l+r)>>1;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
}
}
void pushup(int root)
{
if(tree[root].s){ ///该节点被完全覆盖
tree[root].len=x[tree[root].tr]-x[tree[root].tl-1];
}
else if(tree[root].tl==tree[root].tr){ ///这是一个点而不是一条线段
tree[root].len=0;
}
else {///是一条没有被完全覆盖的区间,合并左右子节点
tree[root].len=tree[root*2].len+tree[root*2+1].len;
}
}
void update(int root,int ql,int qr,int val)
{
int tl=tree[root].tl,tr=tree[root].tr;
if(ql<=tl&&tr<=qr){ ///更新区间包含该节点区间,说明该节点区间被完全覆盖
tree[root].s+=val;
pushup(root);
return;
}
int mid=(tl+tr)>>1;
if(mid>=ql) update(root*2,ql,qr,val);
if(mid<qr) update(root*2+1,ql,qr,val);
pushup(root);
}
int main()
{
int n,T=0;
while(scanf("%d",&n)&&n)
{
int m=0;
for(int i=1;i<=n;i++)
{
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[m].l=x1,a[m].r=x2,a[m].h=y1,a[m].d=1;
x[m++]=x1;
a[m].l=x1,a[m].r=x2,a[m].h=y2,a[m].d=-1;
x[m++]=x2;
}
sort(x,x+m);
sort(a,a+m,cmp);
int len=unique(x,x+m)-x;
// printf("len=%d\n",len);
// for(int i=0;i<=len;i++)
// printf("%d=%f ",i,x[i]);
// puts("");
build(1,1,len);
double sum=0;
for(int i=0;i<m;i++) ///离散化各点,并更新线段树
{
///因为我们的树节点是要记录线段的长度,而不是点的权值
///这里我们可以将a[i].l的位置+1,这样在更新的时候我们就可以a[r]-a[l-1]来计算长度
///这里其实每个叶子节点都代表相邻x的一小段长度
int l=lower_bound(x,x+len,a[i].l)-x+1;
int r=lower_bound(x,x+len,a[i].r)-x;
update(1,l,r,a[i].d);
///tree[1].len表示整个区间的有效长度
sum+=(a[i+1].h-a[i].h)*tree[1].len;
}
printf("Test case #%d\n",++T);
printf("Total explored area: %.2f\n\n",sum);
}
return 0;
}