扫描线

面积并

\(n\) 个四边平行于坐标轴的矩形的面积并。

思路

容易想到计算每一个长方形的面积,然后去掉重叠的面积就为答案。但是重叠的面积并不好算。

于是我们考虑把图形切割成一块一块的小矩形:(图片均来源于网络)
image
那我们只需要计算每个小矩形的面积之和就好了,我们假设有一条直线,从下往上依次截取横边:
image
那我们根据这条扫描线,可以把上图分成3个部分,每个部分宽度可以用两条截取线段高度之差(\(h_{i+1}-h_i\))求得。那我们如何求长呢?

对于每一条横边,\([l_i,r_i]\) 这条部分会被覆盖,最后要求被覆盖的总长度,所以离散化完 \(x\) 坐标后,可以用线段树来实现。

那我们这个线段树需要维护两个信息:

  • 是否被完全覆盖

  • 被覆盖的总长度

那么算总长度只需要 \(tree[1].sum\) 就好了。如何判断当前横边是否还要继续算呢,只需要给矩形的下边赋值为 \(1\),上边赋值为 \(-1\)。这样就不会多算了。

其他与模板一样,只需要修改信息时略微改动:(注意区间左闭右开或左开右闭)

  • 如果该区间被完全覆盖:总和为右端点减左端点。

  • 如果该区间未被完全覆盖:总和为左右两儿子之和。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=7e6+5;
int n,m,ans;
struct st{
	int l,r,c,sum;
}tree[N];
struct node{
	int l,r,h,w;
}line[N];
bool cmp(node a,node b){
	return a.h<b.h;
}
int x[N];
int ls(int p){return p<<1;}
int rs(int p){return p<<1|1;}
void push_up(int p){
	if(tree[p].c){
		tree[p].sum=x[tree[p].r+1]-x[tree[p].l];
	}
	else tree[p].sum=tree[ls(p)].sum+tree[rs(p)].sum;
}
void build(int p,int l,int r){
	tree[p].l=l,tree[p].r=r;
	if(l==r){
		tree[p].c=tree[p].sum=0;
		return;
	}
	int mid=(l+r)>>1;
	build(ls(p),l,mid);
	build(rs(p),mid+1,r);
	push_up(p);
}
void update(int p,int l,int r,int d){
	if(x[tree[p].r+1]<=l||r<=x[tree[p].l]){
		return;
	}
	if(l<=x[tree[p].l]&&x[tree[p].r+1]<=r){
		tree[p].c+=d;
		push_up(p);
		return;
	}
	int mid=(tree[p].l+tree[p].r)>>1;
	update(ls(p),l,r,d);
	update(rs(p),l,r,d);
	push_up(p);
}
signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		int a,b,c,d;
		cin>>a>>b>>c>>d;
		line[2*i-1]={a,c,b,1};
		line[2*i]={a,c,d,-1};
		x[2*i-1]=a;
		x[2*i]=c;
	}
	sort(line+1,line+2*n+1,cmp);
	sort(x+1,x+2*n+1);
	m=unique(x+1,x+2*n+1)-x-1;
	build(1,1,m-1);
	for(int i=1;i<2*n;i++){
		update(1,line[i].l,line[i].r,line[i].w);
		ans+=tree[1].sum*(line[i+1].h-line[i].h);
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2026-03-28 09:12  Azarole  阅读(2)  评论(0)    收藏  举报