OI 扫描线的基本知识(未完成)

10 篇文章 0 订阅
4 篇文章 0 订阅

upd 20220312:新增了算法过程、模板代码

推荐网页:OI Wiki_扫描线

前铺知识

一、扫描线是什么

  • 顾名思义,扫描线是指一条线在图上从下往上扫,并维护一些特定的值。
    在这里插入图片描述
    如图,这几条粉色线把图分成了几个部分。
    在这里插入图片描述
    同样,我们用黄色线又把图分成了另外几个部分。
    这样,我们就可以用底 × × ×高来求出每一个部分的面积,并把它们合起来得到这三个矩形的面积并。

我们从左往右扫(或从下往上,总之有一个顺序),若碰到了一个矩形的左边,就把碰到的这条线段用线段树标记一下,并计算面积。比如,这条线段为 [ 1 , 3 ] [1,3] [1,3],就把数组中下标为 1 − 2 1-2 12 的元素加 1 1 1,也就是用 1 1 1 号元素代表 [ 1 , 2 ] [1,2] [1,2] 这一段,用 2 2 2 号元素代表 [ 2 , 3 ] [2,3] [2,3] 这一段。

若碰到了一个矩形的右边,则把碰到的边在数组中减去,并计算面积。

设上一次碰到便(加入或减去)的横坐标为 x 1 x_1 x1,现在这条边的横坐标为 x 2 x_2 x2,则待计算的若干个矩形宽(上下边)均为 x 2 − x 1 x_2-x_1 x2x1。此时再用线段树求出数组中有标记(值不为 0 0 0)的元素个数求出来,就可以计算出这若干个矩形的面积了。

模板:Luogu P5490

代码:

#include<iostream>
#include<algorithm>
using namespace std;

int n;
struct node
{
	long long x,y,yy,fl;
}line[200010];
struct node1
{
	long long xl,xr,sum,tag;
}tree[8000010];
long long ans;
int s[200010];

bool cmp(node x,node y)
{
	return x.x < y.x;
}

void upd(int x)
{
	if (tree[x].tag)
	{
		tree[x].sum = tree[x].xr - tree[x].xl;
	}
	else tree[x].sum = tree[x * 2].sum + tree[x * 2 + 1].sum;
}

void build(int l,int r,long long x)
{
	tree[x].xl = s[l];
	tree[x].xr = s[r];
	if (l == r) return ;
	if (r - l == 1)
	{
		return ;
	}
	int mid = (l + r) / 2;
	build(l,mid,x * 2);
	build(mid,r,x * 2 + 1);
	upd(x);
}

void add(int x,long long ll,long long rr,int y)
{
	if (tree[x].xl > rr || tree[x].xr < ll)
	{
		return ;
	}
	if (tree[x].xl >= ll && tree[x].xr <= rr)
	{
		tree[x].tag += y;
		upd(x);
		return ;
	}
	if (tree[x * 2].xr >= ll) add(x * 2,ll,min(tree[x * 2].xr,rr),y);
	if (tree[x * 2 + 1].xl < rr) add(x * 2 + 1,max(tree[x * 2 + 1].xl,ll),rr,y);
	upd(x);
}

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++)
	{
		int x,y,xx,yy;
		cin >> x >> y >> xx >> yy;
		line[i] = (node){x,y,yy,1};
		line[i + n] = (node){xx,y,yy,-1};
		s[i] = y;
		s[i + n] = yy; 
	}
	sort(s + 1,s + 2 * n + 1);
	sort(line + 1,line + 2 * n + 1,cmp);//按x排序
	build(1,2 * n,1);
	add(1,line[1].y,line[1].yy,line[1].fl);
	for (int i = 2;i <= 2 * n;i ++)
	{
		ans += (line[i].x - line[i - 1].x) * tree[1].sum;
		add(1,line[i].y,line[i].yy,line[i].fl);
	}
	cout << ans << endl;
}

一点五、离散化

  • 听起来很高级,实际上就是以 y y y轴排序。。。

二、例题

HDU Atlantis 点我
luogu P1856 点我

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值