欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

扫描线+线段树

程序员文章站 2022-03-02 10:55:54
...

上次写了个扫描线+线段树的扫描线,扫描线的其实可以再优化,今天来说说线段树优化的扫描线。

扫描线的思路很简单,设有多个矩形,求面积并的时候,可以将每个矩形用两个四元组表示,扫描线+线段树,其中扫描线+线段树是矩形的的左下角和右上角横坐标的其中一个,扫描线+线段树是左下角和右上角的两个纵坐标扫描线+线段树扫描线+线段树有两个值,1和-1,含义是从左向右扫描的时候的入边和出边。扫描的时候第一次碰到的就是入边,另外一个是出边,因为是从左向右扫描,所以扫描线+线段树坐标小的是入边。然后我们就得到了扫描线+线段树个四元组,将他们按照扫描线+线段树从小到大排序。然后将所有的扫描线+线段树坐标放入一个数组中,排序去重,离散化。之前扫描线+线段树的做法是用一个数组的每个值去维护一个区间,这样每次更新的时候需要扫一遍数组,求解的时候也扫一遍,其实可以用线段树去维护这样一个区间。

线段树维护两个值,当前区间被覆盖的次数,和区间内的被覆盖过的边的长度和,可以再多一个,表示当前区间的长度,方便计算。如果当前区间被覆盖了,显然长度和扫描线+线段树,如果没有覆盖就是扫描线+线段树,更新的时候,由于有入边就有出边,所以前面的扫描线+线段树一定会被后面的扫描线+线段树抵消掉,就用不到标记下传了。

注意:一定是先计算再更新。

#include <bits/stdc++.h>
using namespace std;
const int N = 310;
struct p{
	int x, y1, y2, mark;
} a[N];
int x[N], y[N];
int dy[N];
int len;
typedef struct SegementTree{
	int l[N * 4];
	int r[N * 4];
	int sum[N * 4];
	int cnt[N * 4];
	int length[N * 4];
	void build(int ll, int rr, int k){
		l[k] = ll;
		r[k] = rr;
		sum[k] = 0;
		cnt[k] = 0;
		if (ll == rr){
			length[k] = dy[ll + 1] - dy[ll];
			return;
		}
		int mid = (ll + rr) / 2;
		build(ll, mid, k << 1);
		build(mid + 1, rr, k << 1 | 1);
		length[k] = length[k << 1] + length[k << 1 | 1];
	}
	void update(int ll, int rr, int k, int mark){
		if (l[k] >= ll && r[k] <= rr){
			cnt[k] += mark;
			sum[k] = cnt[k] ? length[k] : sum[k << 1] + sum[k << 1 | 1];
			
			return ;
		}
		int mid = l[k] + r[k];
		mid /= 2;
		if (ll <= mid)update(ll, rr, k << 1, mark);
		if (rr > mid)update(ll, rr, k << 1 | 1, mark);
		sum[k] = cnt[k] ? length[k] : sum[k << 1] + sum[k << 1 | 1];
	}
} ST;
bool cmp(p& a, p& b){
	return a.x < b.x;
}
int get(int x){
	return lower_bound(dy + 1, dy + 1 + len, x) - dy;
}
ST st;
int main()
{
	freopen("./in.in", "r", stdin);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++){
		scanf("%d %d", x + i, y + i);
		scanf("%d %d", x + i + n, y + i + n);
		a[i].x = x[i];
		a[i].y1 = y[i];
		a[i].y2 = y[i + n];
		a[i].mark = 1;
		a[i + n].x = x[i + n];
		a[i + n].y1 = y[i];
		a[i + n].y2 = y[i + n];
		a[i + n].mark = -1;
		dy[i] = y[i];
		dy[i + n] = y[i + n];
	}
	sort(a + 1, a + 1 + n, cmp);
	sort(dy + 1, dy + 1 + n + n);
	len = unique(dy + 1, dy + 1 + n + n) - dy - 1;
	st.build(1, len - 1, 1);
	int res = 0;
	for (int i = 1; i <= n + n; i++){
                //顺序不能错
		res += st.sum[1] * (a[i].x - a[i - 1].x);
		st.update(get(a[i].y1), get(a[i].y2) - 1, 1, a[i].mark);
	}
	printf("%d\n", res);
	return 0;
}