参考:https://blog.csdn.net/tomorrowtodie/article/details/52048323
Overlapping Rectangles
矩形面积并 经典的扫描线问题
扫描线可以想象成一根假想的线,
将图从左往右或从右往左或自下而上或自上而下“扫描”一遍
可以看到6根扫描线将图像分成了5个部分
各个颜色就是是有效面积,
假设从下往上看,首先,看到了最下面灰色矩形的下边,
用这个下边的长度(宽)乘以这条边和上一条边的高度差(高)即得到灰色矩形面积,
继续看到蓝色的矩形的下边,虽然蓝色矩形有两个,
但我们计算时自然会用结合律将两个矩形的下边加起来再去乘以同样的高,
然后重复这样的操作,我们最终可以求得整个图形的面积。
机器是这样实现的
存图,只需要保存这张图里面的所有水平的边
边的属性:边的左右端点(横坐标),边的高度(纵坐标),边属于矩形的上边还是下边
排序,因为要从下往上以次扫描
离散,因为题目中给的数据往往是浮点数或者是给定区间范围很大
计算有效面积的‘宽’ 用到了线段树
怎么去维护这个区间的有效长度(即被覆盖的长度)
因为是从上而下的扫这个图,
在同一个矩阵中,扫到下边相当于刚刚进入这个矩形,扫到上边则是要离开这个矩形
那么如果有扫描线在这个矩阵中间,那么中间的扫描线肯定会有这个矩阵的有效长度,
所以线段树会随着扫描线的移动而记录有效长度
如果扫到的这条边是某矩形的下边,则往区间插入这条线段
表示在没到这个矩阵上边的时候,这个区间是有效长度
如果扫到的这条边是某矩形的上边,则往区间删除这条线段
表示这个区间不是有效长度
计算有效面积的‘高’ 两个扫描线之间的高
AC code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define maxn 5010
struct node{
int ss;
double l,r,h;
node(double l1=0,double r1=0,double h1=0,int ss1=0){
l=l1;
r=r1;
h=h1;
ss=ss1;
}
}edge[maxn<<2];
int add[maxn];
double x[maxn<<2],sum[maxn<<2];
bool cmp(node a,node b){
return a.h<b.h;
}
void pushup(int now,int l,int r){
if(add[now]) sum[now]=x[r+1]-x[l];
else if(l==r) sum[now]=0;
else sum[now]=sum[now<<1]+sum[now<<1|1];
}
void update(int now,int L,int R,int val,int l,int r){
if(L<=l&&r<=R){
add[now]+=val;
pushup(now,l,r);
return ;
}
int mid=(l+r)>>1;
if(L<=mid) update(now<<1,L,R,val,l,mid);
if(R>mid) update(now<<1|1,L,R,val,mid+1,r);
pushup(now,l,r);
}
int main(){
int n;
double x1,x2,y1,y2,ans;
while(cin>>n && n){
ans=0;
int top=0,l,r;
for(int i=0;i<n;i++){
cin>>x1>>y1>>x2>>y2;
x[top]=x1;
edge[top++]=node(x1,x2,y1,1);
x[top]=x2;
edge[top++]=node(x1,x2,y2,-1);
}
sort(x,x+top);
sort(edge,edge+top,cmp);
int k = 1;
for(int i=1; i<top; i++)
{
if(x[i] != x[i-1])
x[k++] = x[i];
}
memset(add,0,sizeof(add));
memset(sum,0,sizeof(sum));
for(int i=0; i<top-1; i++){
l=lower_bound(x,x+k,edge[i].l)-x;
r=lower_bound(x,x+k,edge[i].r)-x-1;
update(1,l,r,edge[i].ss,0,k-1);
ans+=(sum[1]*(edge[i+1].h-edge[i].h));
}
cout<<(int)ans<<endl;
}
cout<<"*"<<endl;
return 0;
}