题目链接
题意:
给你n个矩形,问这些矩形所覆盖的面积是多少,如下图
就是两个矩形覆盖的总面积。
分析:
这个题我一开始想的时候直接没往线段树上想,因为这个是double类型的,线段树在我的认知看来都是int类型的,而且这个东西是二维的面积,怎么会和线段树有关呢qaq,但是这个题就是用线段树扫描线做出来的,具体是怎么扫描的呢,下面来看个图片。
假如蓝色的部分是题目中给出的矩形,红色的线是对于每个x坐标画出的线,那么对于每段区间(x[i],x[i+1]),只需要找出矩形的高度即可,如x1~x2,就是两个绿色矩形的高加起来,那么这一部分的答案就是底乘高,现在咱们的当务之急就是对于每段区间,都能找到那个对应的高度,那么咱们就可以用线段树来维护每段区间的高度和,每个结构体中有l,r,len,cnt四个变量,其中len代表的是这个区间的高度,cnt代表的是这个区间被多少个矩形覆盖着,下面具体请看代码:
#include<bits/stdc++.h>
#define ll (k<<1)
#define rr (k<<1|1)
#define Mid (tr[k].r + tr[k].l >> 1)
#define Len (tr[k].r - tr[k].l + 1)
using namespace std;
const int N = 10010;
vector<double> alls;
struct node{
double x,y1,y2;
int k;
bool operator<(const node&t)const{
return x < t.x;
}
}seg[N*2];
struct Node{
int l,r,cnt;
double len;
}tr[N<<3];
int n;
int find(double x){
return lower_bound(alls.begin(),alls.end(),x) - alls.begin();
}
void pu(int k){
if(tr[k].cnt) tr[k].len = alls[tr[k].r+1] - alls[tr[k].l];
else if(tr[k].l == tr[k].r) tr[k].len = 0;
else if(tr[k].cnt == 0) tr[k].len = tr[ll].len + tr[rr].len;
}
void build(int k,int l,int r){
tr[k] = {l,r,0,0};
if(l == r) return;
build(ll,l,Mid);
build(rr,Mid+1,r);
pu(k);
}
void update(int k,int l,int r,int val){
if(tr[k].l >= l && tr[k].r <= r){
tr[k].cnt += val;
pu(k);
return;
}
if(l <= Mid) update(ll,l,r,val);
if(r > Mid) update(rr,l,r,val);
pu(k);
}
int main(){
int T = 1;
while(scanf("%d",&n),n){
alls.clear();
for(int i=0,j=0;i<n;i++){
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
seg[j++] = {x1,y1,y2,1};
seg[j++] = {x2,y1,y2,-1};
alls.push_back(y1);
alls.push_back(y2);
}
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
build(1,0,alls.size()-2);
double ans = 0;
sort(seg,seg+n*2);
for(int i=0,j=0;i<2*n;){
if(i > 0) ans += tr[1].len * (seg[i].x - seg[i-1].x);
j = i;
while(i < 2*n && seg[i].x == seg[j].x) j++;
while(i < j){
int l = find(seg[i].y1),r = find(seg[i].y2)-1;
update(1,l,r,seg[i].k);
i++;
}
}
printf("Test case #%d\n",T++);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}