线段树+扫描线

扫描线

扫描线问题主要利用了线段树。

因为矩形的并集比较难算,所以我们可以用(sum)(扫描线被截长度×所扫描的高度)来求和。而这样做发现可以用线段树来优化,具体优化方式如下:所扫描的高度比较好求,主要是扫描线被截长度需要优化。

我们可以设横边有一个a权值,如果该边是矩阵的下边则设为1,相反就设为-1,这样如果一段区间(如果该区间正好与横边对应的话至少会对应两个边)的没有被截(或者说已经扫过去,加入答案中去了)则此时该区间所对应的线段树的a权值和一定为0.

相反,如果该区间已经被扫描线扫进去且会更新答案的话,则a权值一定不为0。

然后枚举每一条边,在线段树中更新a值和被覆盖长度的值。

最后答案加上总区间被覆盖长度的值的和乘高度差。

#include <bits/stdc++.h>
#define int long long
#define ls l, mid, root << 1
#define rs mid + 1, r, root << 1 | 1
using namespace std;	
int n, cnt, _x1, _x2, _y9, _y3, x[1001000], sum;
struct g {				
 	int l, r, y, s;		
 	bool operator < (g c) {
 		return y < c.y;	
 	}					
}data[1001000];			
struct node {			
 	int l, r, a, len;	
}ans[4001000];			
void build(int l, int r, int root) {
 	ans[root].l = l, ans[root].r = r;
 	ans[root].len = ans[root].a = 0;
 	if (l == r) return; 
 	int mid = (l + r) >> 1;
 	build(ls);
 	build(rs);
 	return;
}
inline void pushup(int root)
{
	if (ans[root].a)//如果当前已经被覆盖 
 		ans[root].len = x[ans[root].r + 1] - x[ans[root].l];//那就完全被覆盖了,就直接加上就好。 
 	else//没有被覆盖的就需要递归求解
		ans[root].len = ans[root << 1].len + ans[root << 1 | 1].len;
}
void update(int ql, int qr, int root, int add)
{
	int l = ans[root].l, r = ans[root].r;
	if (x[l] >= qr || x[r + 1] <= ql) return;
	if (ql <= x[l] && x[r + 1] <= qr)	
	{									
		ans[root].a += add;
		pushup(root);//完成操作后记得要更新,查看是否被覆盖了 
		return;
	}
 	update(ql, qr, root << 1, add);
 	update(ql, qr, root << 1 | 1, add);
	pushup(root);
}
signed main()
{
 	scanf("%lld", &n);//初始化 
 	for (int i = 1; i <= n; i++)
 	{
 	 	scanf("%lld%lld%lld%lld", &_x1, &_y9, &_x2, &_y3);
 	 	data[++cnt].l = _x1, data[cnt].r = _x2, data[cnt].s = 1, data[cnt].y = _y9; 
 	 	x[cnt] = _x1;
 	 	data[++cnt].l = _x1, data[cnt].r = _x2, data[cnt].s = -1, data[cnt].y = _y3;
 	 	x[cnt] = _x2;				
 	} //离散化					   
 	sort(data + 1, data + 1 + cnt);//离散化首先需要排序+去重
 	sort(x + 1, x + 1 + cnt);	   
 	int block = unique(x + 1, x + 1 + cnt) - (x + 1);
 	build(1, block - 1, 1); //block-1就可以包含所有的区间了。建树时的都是离散化之后的点 
 	for (int i = 1; i < cnt; i++)
	{
 	  	update(data[i].l, data[i].r, 1, data[i].s);//更新扫描线信息
 	  	sum += ans[1].len * (data[i + 1].y - data[i].y);//面积=底X高 ,更新面积, 
	}   
	printf("%lld", sum);
	return 0;
}       
原文地址:https://www.cnblogs.com/liuwenyao/p/11353119.html