矩形切割———计算多个矩形的总面积
首先,看看这个:
没错,这是个面积为 \(4\) 的矩形,那么两个这样的矩形面积就是 \(8\) 了
但是真的是这样吗?
那么这是一个面积为 \(9\) 的和一个面积为 \(1\) 的矩形,他的面积可不是 \(9+1=10\),他重叠了!!
对于不重叠的矩形,把面积一个个加起来很简单
那对于重叠的矩形呢?开二维数组打标记?
那你就天真了!!!
你看看这道题
大体就是说在一个平面坐标系里,我给你\(N(N≤1000)\)个矩形,我告诉你他们左上角和右下角的坐标,然后然你求矩形覆盖区域的面积。
注意:坐标的范围在\(-10^8\)~\(10^8\)之间,来你给我开二维数组打个标记来。
很显然不行,那我们就会想到离散化缩小常数。
但这道题别想,超时,最多90分。
那咋办?
让我们这么想,我们有两个矩形,先把一个矩形放到坐标系中,然后发现另一个矩形与其有重叠部分,然后我们用后一个矩形把前一个矩形没有被遮盖的部分切下来,单独分成多个小矩形,然后把后一个矩形直接放上去。
再来一个矩形,用他分别去切我前面的所有矩形,然后放到坐标系里,以此类推,最后暴力枚举所有小矩形,把面积加起来就 \(OK\) 了。
我知道不形象,上图:
这两个矩形重叠了对吧,蓝色部分是矩形,而绿色部分不规则了。
那我们就让他规则!
现在全是矩形了,没有不规则的了。这就是矩形切割,那么怎么实现呢?
#include<bits/stdc++.h>
#define ll long long
#define Konnyaku std
using namespace Konnyaku;
ll read()
{
ll x=0;bool f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f?x:(~x)+1;
}
struct node{
ll x1,x2,y1,y2;
}a[100005];//存矩形
int n,top;
ll X1,X2,Y1,Y2;
void ADD(ll x1,ll x2,ll y1,ll y2){a[++top]=(node){x1,x2,y1,y2};}
void cuts(int jx,ll x1,ll x2,ll y1,ll y2,bool pd)//这个pd是为了分别进行切割横坐标和纵坐标。
{
if(pd){//切割横坐标
ll k1=max(a[jx].x1,x1),k2=min(a[jx].x2,x2);//分别比较来的矩形和被切割矩形的左上角,右下角两个横坐标
if(k1>a[jx].x1)ADD(a[jx].x1,k1,a[jx].y1,a[jx].y2);//切下左边部分;
if(k2<a[jx].x2)ADD(k2,a[jx].x2,a[jx].y1,a[jx].y2);//切下右边部分;
cuts(jx,k1,k2,y1,y2,0);//切纵坐标去,因为矩形已经被切了一部分了,不能重复切,所以处理一下切矩形的矩形,把冗余部分去掉。
}
else {//切割纵坐标
ll k1=min(a[jx].y1,y1),k2=max(a[jx].y2,y2);//比较纵坐标
if(k1<a[jx].y1)ADD(x1,x2,a[jx].y1,k1);//切下上半部分;
if(k2>a[jx].y2)ADD(x1,x2,k2,a[jx].y2);//切下下半部分;
}
}
int main()
{
n=read();
X1=read();Y1=read();X2=read();Y2=read();
ADD(X1,X2,Y1,Y2);//先把第一个矩形加进去
for(int js=1;js<n;++js)
{
X1=read();Y1=read();X2=read();Y2=read();
for(int i=1;i<=top;++i)//和每一个矩形作比较
{
if(X1>=a[i].x2||X2<=a[i].x1||Y1<=a[i].y2||Y2>=a[i].y1)continue;//如果没有重叠就不管
cuts(i,X1,X2,Y1,Y2,1);//重叠了就切他
a[i]=a[top];//当前这个矩形已经被切了,没有了,把他踢出去(用最后一个小矩形代替他)
--top;//最后一个来到a[i]了,把a[top]踢出去
--i;//确保扫描到每一个矩形
}
ADD(X1,X2,Y1,Y2);//把新来的这个矩形加上。
}
ll ans=0;
for(int i=1;i<=top;i++)//枚举每一个小矩形,因为不重叠了,所以直接把面积加起来即可
ans+=(a[i].x2-a[i].x1)*(a[i].y1-a[i].y2);
printf("%lld",ans);
}
于是我们就在大约 \(N^2\)(好像比这要多,因为矩形越来越多)的复杂度完成了一个常数极大的矩形覆盖面积问题。
\(VERY GOOD\)