P5490 【模板】扫描线(扫描线求面积)

题目链接:点击这里

题目大意:
给出 n n n 个矩形的对角坐标求矩形面积的交集

题目分析:
我们考虑用从下而上扫描的扫描线,先要离散化一下 x x x 的坐标,来减小线段树的大小
线段树有一些细节:
1.要注意因为线段树维护的是线段长度而不是点权,所以需要做出改变, [ l , r ] [l,r] [l,r] 维护的是 x r + 1 − x l x_{r+1}-x_l xr+1xl
2.因为线段树右端点的意义已经变化了,所以线段树只需要维护 c n t − 1 cnt-1 cnt1 个元素( c n t cnt cnt x x x 数组离散化后的元素个数)
3.写 p u s h u p pushup pushup 时要注意叶子节点没有儿子需要特判,否则会数组越界
最终的答案就是线段树根节点维护的线段长度乘上当前线段与下一条线段的高度差

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
//#define int ll
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double eps = 1e-8;
struct node{
	int sum;ll len;
}a[maxn<<2];
struct Line{
	int l,r,h,flag;
	bool operator < (const Line &b) const {
		return h < b.h;
	}
}line[maxn];
int n,X[maxn],val[maxn];
void pushup(int root,int l,int r)
{
	if(a[root].sum) a[root].len = X[r+1]-X[l];
	else if(l != r)a[root].len = a[root<<1].len+a[root<<1|1].len;
	else a[root].len = 0;
}
void updat(int root,int l,int r,int ql,int qr,int val)
{
	if(X[l]>=qr || X[r+1]<=ql) return ;
	if(X[l]>=ql && X[r+1]<=qr)
	{
		a[root].sum += val;
		pushup(root,l,r);
		return ;
	}
	int mid = l+r>>1;
	updat(root<<1,l,mid,ql,qr,val);
	updat(root<<1|1,mid+1,r,ql,qr,val);
	pushup(root,l,r);
}
int main()
{
	n = read();
	for(int i = 1;i <= n;i++)
	{
		int x = read(),y = read(),xx = read(),yy = read();
		line[2*i-1] = (Line){x,xx,y,1};
		line[2*i] = (Line){x,xx,yy,-1};
		X[2*i-1] = x,X[2*i] = xx;
	}
	n <<= 1;
	sort(line+1,line+n+1);
	sort(X+1,X+n+1);
	int cnt = unique(X+1,X+n+1)-X-1;
	ll ans = 0;
	for(int i = 1;i < n;i++)
	{
		updat(1,1,cnt-1,line[i].l,line[i].r,line[i].flag);
		ans += a[1].len*(line[i+1].h-line[i].h);
	}
	printf("%lld\n",ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值