扫描线结合线段树求矩形面积并

https://www.luogu.com.cn/problem/P5490

题意概述

给定二维平面上一系列矩形的四个坐标,求所有矩形的面积并。

思路

考虑对 \(x\) 轴做扫描线,每个事件触发前累加一次面积,\(y\) 轴覆盖的区域用线段树维护。线段树维护区间的有效长度和被整体覆盖的次数,如果整体覆盖次数大于 \(1\),有效长度为区间长度,否则为左右孩子的有效长度之和,不需要懒标记。注意 \(y\) 轴坐标需要离散化。


//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

class node{
public:
	ll len=0,cover=0;
	int cnt=0;
};


void solve(){
	int n;
	cin >> n;

	vector<ll> uni{0};
	vector<array<ll,4>> a(n);

	for (int i=0;i<n;i++){
		ll x1,y1,x2,y2;
		cin >> x1 >> y1 >> x2 >> y2;

		uni.push_back(y1);
		uni.push_back(y2);

		a[i] = {x1,x2,y1,y2};
	}

	sort(uni.begin()+1,uni.end());
	uni.erase(unique(uni.begin()+1,uni.end()),uni.end());
	int m = uni.size()-1;

	vector<node> seg(4*m+1);

	function<void(int,int,int)> build = [&](int rt,int l,int r){
		if (l==r){
			seg[rt].len = uni[l]-uni[l-1];
			return;
		}	

		int mid = l+r >> 1;

		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);

		seg[rt].len = seg[rt<<1].len+seg[rt<<1|1].len;
	};

	function<void(int,int,int,int,int,int)> update_range = [&](int rt,int l,int r,int x,int y,int v){
		if (r<x || l>y){
			return;
		}

		if (x<=l && y>=r){
			seg[rt].cnt += v;
			
			if (seg[rt].cnt>0){
				seg[rt].cover = seg[rt].len;
			}
			else{
				if (l!=r) seg[rt].cover = seg[rt<<1].cover+seg[rt<<1|1].cover;
				else seg[rt].cover = 0;
			}

			return;
		}

		int mid = l+r >> 1;
		update_range(rt<<1,l,mid,x,y,v);
		update_range(rt<<1|1,mid+1,r,x,y,v);

		if (seg[rt].cnt>0){
			seg[rt].cover = seg[rt].len;
		}
		else{
			seg[rt].cover = seg[rt<<1].cover+seg[rt<<1|1].cover;
		}
	};

	build(1,1,m);

	vector<array<ll,4>> wait;

	for (int i=0;i<n;i++){
		auto& [x1,x2,y1,y2] = a[i];	

		wait.push_back({x1,y1,y2,0});
		wait.push_back({x2,y1,y2,1});
	}

	sort(wait.begin(),wait.end());

	ll res = 0;
	ll pre = INF;

	for (auto& [x,y1,y2,op]:wait){
		if (pre==INF){
			pre = x;
		}

		res += (x-pre)*seg[1].cover;

		int p1 = lower_bound(uni.begin()+1,uni.end(),y1)-uni.begin();
		int p2 = lower_bound(uni.begin()+1,uni.end(),y2)-uni.begin();

		update_range(1,1,m,p1+1,p2,op==0?1:-1);

		pre = x;
	}

	cout << res << '\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	// cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-04-29 11:28  kzssCCC  阅读(15)  评论(0)    收藏  举报