扫描线

求矩形面积并,把矩阵竖着割开,累加。

矩形 \((x_1,y_1,x_2,y_2)\) 分成 \((x1,y1,y2,1)\)\((x2,y1,y2,-1)\) 两条线,指的是,\(x=x_i(y_1\leq x\leq y_2)\) 这样的线,土 \(1\) 指的是加上或减去。

需要离散 flower,主要是 SGT。

不断维护当前的矩阵高,线段树搞。

线段树要维护 当前区间覆盖次数|区间总高度。

因为是修改成对,所以可以 乱搞 简单搞 qwq

把实际上的组成区间 \(cnt\) 改掉,每次上传 \(pushup\)

当前节点 \(cnt>0\) 的情况 \(len=\) 区间实际长度,不然是左右子树 \(len\) 和。

注意开 \(16n\) 空间,划分 \(*2\) 线段树 \(*8\) /fad

#include<bits/stdc++.h>
#define int long long
#define MN 1600010
#define ls(p) (p<<1)
#define rs(p) (p<<1|1) 

using namespace std;

int n, raw[MN], cnt[MN], len[MN];
int top, tot, ans;

struct dat {
	int x, l, r, k;
	dat() {}
	dat(int xx,int ll,int rr,int kk)
		{ x=xx, l=ll, r=rr, k=kk; }
} p[MN];

bool cmp(dat u,dat v)
	{ return u.x<v.x; }

inline void up(int p,int s,int e) {
	if(cnt[p]) len[p]=raw[e]-raw[s];
	else len[p]=len[ls(p)]+len[rs(p)];
}

void upt(int p,int s,int e,int l,int r,int v) {
	if(l>=raw[e]||raw[s]>=r) return;
	if(l<=raw[s]&&raw[e]<=r) {
		cnt[p]+=v;
		up(p,s,e);
		return;
	}
	int mid=(s+e)>>1;
	upt(ls(p),s,mid,l,r,v);
	upt(rs(p),mid,e,l,r,v);
	up(p,s,e);
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n;
    for(int i=1; i<=n; ++i) {
    	int x1, y1, x2, y2;
    	cin >> x1 >> y1 >> x2 >> y2;
    	p[++top]=dat(x1,y1,y2,1), raw[top]=y1;
    	p[++top]=dat(x2,y1,y2,-1), raw[top]=y2;
    }
	sort(raw+1,raw+1+top);
	for(int i=1; i<=top; ++i)
		if(raw[i]!=raw[i-1]) raw[++tot]=raw[i];
    sort(p+1,p+1+top,cmp);
    for(int i=1; i<top; ++i) {
    	upt(1,1,tot,p[i].l,p[i].r,p[i].k);
    	ans+=(p[i+1].x-p[i].x)*len[1];
    }
    cout << ans;
    return 0;
}
posted @ 2023-08-12 22:54  Hypoxia571  阅读(13)  评论(0编辑  收藏  举报