Atlantis
题意:求n个矩形合成图形的面积,如下图是由三个矩形构成,求出所涂颜色区域的面积;
当图形很少时可以暴力求解,S=S红+S紫+S蓝;但是这样是很麻烦的,怎样让他简单化呢?
观察一下上图的墨绿线,这些线很好的将原图划分为五部分,面积就是这五部分和,这就是扫描线;
我们可以把墨绿线看作是由左向右移动的,当他碰到一条边的时候暂停一下,那么第一部分的面积一定是该处的边的长度L乘下一条边距离此处的距离D,然后继续向右移动,遇到第二条边再停止,计算第二部分面积,... ... ,知道移动到最后一条边处,停止计算;
D很好算,把所有边排序后,直接后减前;但是L是由多个边构成的不好算;这里就用到了线段树了,用线段树记录并合并区间长度;
通常线段树是这样的:
每个结点存的但单点,而线段是连续的;如果线段[1, 3]存入线段树,会直接存入1-2和3两个节点,计算其长度时是2-1+3-3=2,就造成了信息缺失现象,所以对于线段[l, r]我们应该 以[l, r-1]的形式存入,计算长度时为l+1-r;
#include <bits/stdc++.h>
using namespace std;
struct Line{//存边
double x, y1, y2;
int v;//记录该边时矩形的起始边还是终止边,前者1后者-1;
Line(){}
Line(double x0, double y10, double y20, int v0){
x=x0, y1=y10, y2=y20, v=v0;
}
bool operator < (const Line &p) const{
return x<p.x;
}
}line[300];
double y[300];
int cnt_y, cnt_l;
struct node{
int l, r, v;//v表示[l, r]区间是否被覆盖;
double len;//[l, r]区间被覆盖长度;
}tr[1000];
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].v=0;
if(l==r) return;
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
}
void pushup(int m){//计算区间被覆盖长度;
if(tr[m].v) tr[m].len=y[tr[m].r+1]-y[tr[m].l];//整个区间被覆盖时,长度是整个区间长度;
else if(tr[m].l==tr[m].r) tr[m].len=0;//叶节点为0;
else tr[m].len=tr[m<<1].len+tr[m<<1|1].len;//为被全部覆盖时,长度为子区间被覆盖长度和;
}
void updata(int m, int l, int r, int v){
if(tr[m].l==l&&tr[m].r==r){
tr[m].v+=v;
pushup(m);
return;
}
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid) updata(m<<1, l, r, v);
else if(l>mid) updata(m<<1|1, l, r, v);
else{
updata(m<<1, l, mid, v);
updata(m<<1|1, mid+1, r, v);
}
pushup(m);
}
int main(){
int n, cas=0;
double x1, x2, y1, y2;
while(scanf("%d", &n), n){
cas++;
cnt_l=cnt_y=0;
for(int i=0; i<n; i++){
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
y[++cnt_y]=y1;
y[++cnt_y]=y2;
line[++cnt_l]=Line(x1, y1, y2, 1);
line[++cnt_l]=Line(x2, y1, y2, -1);
}
sort(line+1, line+1+cnt_l);
sort(y+1, y+1+cnt_y);
cnt_y=unique(y+1, y+1+cnt_y)-(y+1);//去重点,离散y;
build(1, 1, cnt_y);
double ans=0.0;
for(int i=1; i<=cnt_l; i++){
int l=upper_bound(y+1, y+1+cnt_y, line[i].y1)-(y+1);
int r=upper_bound(y+1, y+1+cnt_y, line[i].y2)-(y+1)-1;//存入区间是[l, r-1];
updata(1, l, r, line[i].v);
ans+=tr[1].len*(line[i+1].x-line[i].x);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", cas, ans);
}
return 0;
}