覆盖的面积
题意:若干矩形重叠在一起,求出重叠部分的面积之和,如下图,求出红色区域面积;
之前算过整个图形的面积,而今要算重叠部分的面积,还是原来的思路,接着动用那条墨绿的扫描线;
和之前有些许不同的是扫描线要扫过两次才能出现重叠区域,那么如何用线段树维护区间[l, r]被覆盖次数大于1的长度呢?
先回想一下用线段树维护区间[l, r]被覆盖的长度的算法:
分三种情况:
一:[l, r]被完全覆盖,len=r+1-l;(线段存入线段树的不同点,[l, r]存入线段树时存入的是[l, r-1]);
二:[l, r]是个叶子,len=0;
三:[l, r]未被完全覆盖,len=左右子区间被覆盖长度和;
那么维护区间[l, r]被覆盖次数大于1的长度能不能同样的分为三部分呢?
一:[l, r]全部被覆盖2次及以上,len=r+1-l;
二:[l, r]是个叶子, len=0;
三:[l, r]没有全部被覆盖2次及以上;这时就不一样了,还能在分成两种情况:
3.1:[l, r]全部被覆盖,但只有部分是被覆盖2次及以上, len=左右子区间被覆盖1次及以上长度之和;why?如果之前子区间已经被覆盖了1次了,那么来到父区间,不久又被覆盖了一次嘛,所以得出结果;
3.2:[l, r]只有部分被覆盖,len=左右子区间被覆盖2次及以上长度之和;这里就比较好理解了;
综上所述,求区间[l, r]被覆盖两次及以上长度分为四种情况;
#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
struct Line{
double y, x1, x2;
int v;
Line(){}
Line(double y0, double x10, double x20, int v0){
y=y0, x1=x10, x2=x20, v=v0;
}
bool operator < (const Line &p) const {
return y<p.y;
}
}line[maxn<<1];
double x[maxn<<1];
int cnt_l, cnt_x;
struct node{
int l, r, v;
double len1, len2;
}tr[maxn<<3];
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].v=0;
tr[m].len1=tr[m].len2=0.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].len1=x[tr[m].r+1]-x[tr[m].l];
}else if(tr[m].l==tr[m].r){
tr[m].len1=0;
}else{
tr[m].len1=tr[m<<1].len1+tr[m<<1|1].len1;
}
if(tr[m].v>1){
tr[m].len2=x[tr[m].r+1]-x[tr[m].l];
}else if(tr[m].l==tr[m].r){
tr[m].len2=0;
}else if(tr[m].v==1){
tr[m].len2=tr[m<<1].len1+tr[m<<1|1].len1;
}else{
tr[m].len2=tr[m<<1].len2+tr[m<<1|1].len2;
}
}
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 T;
double x1, x2, y2, y1;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
cnt_l=cnt_x=0;
for(int i=0; i<n; i++){
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
x[++cnt_x]=x1;
x[++cnt_x]=x2;
line[++cnt_l]=Line(y1, x1, x2, 1);
line[++cnt_l]=Line(y2, x1, x2, -1);
}
sort(line+1, line+1+cnt_l);
sort(x+1, x+1+cnt_x);
cnt_x=unique(x+1, x+1+cnt_x)-(x+1);
build(1, 1, cnt_x);
double ans=0.0;
for(int i=1; i<=cnt_l; i++){
int l=upper_bound(x+1, x+1+cnt_x, line[i].x1)-(x+1);
int r=upper_bound(x+1, x+1+cnt_x, line[i].x2)-(x+1)-1;
updata(1, l, r, line[i].v);
ans+=(line[i+1].y-line[i].y)*tr[1].len2;
}
printf("%.2lf\n", ans);
}
return 0;
}