首页 > 其他分享 >扫描线

扫描线

时间:2024-08-26 08:57:54浏览次数:5  
标签:底边 int 线段 扫描线 区间 矩形

扫描线

经典问题之求矩形面积并,可以使用线段树和扫描线。

比方说我们要对这俩东西求面积并,我们简单分割一下。

然后扫描线就是,从最下面一条绿线向上扫过去,遇到下底边则加上这个矩形,遇到上底边则减去这个矩形。

回到这道题,发现给了我们矩形的两个角,那么上底边和下底边是好求的。

发现这样对图形分层之后,每部分的高是好求的,就是所有底边排个序两两做差。于是考虑求底的长度。

这几条绿线把 \(x\) 轴分成了 \(5\) 部分,显然 \(1,5\) 两部分没什么用,所以忽略不计。

我们对 \(2,3,4\) 三部分建立线段树,线段树的叶子维护一个区间的线段的信息。

然后我们依次扫过所有边,显然只有 \(2\times n\) 条。

我们对于每个区间维护四个东西,分别是:这个区间在线段树中的下标范围,当前区间被几个矩形完整覆盖,当前区间被覆盖的长度。

这里简单说一下上传:考虑当前矩形是否被完全覆盖。如果是,那么长度直接为这个区间所能达到的最大长度,否则从两个儿子更新。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 100005
using namespace std;
int n,x[N<<1];
struct line{
	int l,r,h,flag;
	bool operator<(const line &t)const{
		return h<t.h;
	}
}l[N<<1];
struct node{
	int l,r,sum,len;
	//l,r区间左右端点
	//sum该区间被几个矩形完全覆盖
	//len该区间被覆盖的长度 
}tr[N<<4];
//需要开16倍,因为pushup中会访问到这么大的点,虽然这个点啥也没存 
void pushup(int u){
	int l=tr[u].l,r=tr[u].r;
	if(tr[u].sum!=0)tr[u].len=x[r+1]-x[l];
	//被完全覆盖则不能用子区间更新,因为子节点没有记录信息 
	else tr[u].len=tr[u<<1].len+tr[u<<1|1].len;
}
void build(int u,int l,int r){
	tr[u]={l,r,0,0};
	if(l==r)return;
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
	//其实pushup没必要,都是0 
}
void modify(int u,int L,int R,int add){
	int l=tr[u].l,r=tr[u].r;
	if(x[r+1]<=L||x[l]>=R)return;
	//完全无交,直接返回 
	if(x[l]>=L&&x[r+1]<=R){
		tr[u].sum+=add;
		pushup(u);
		return; 
		//把这个区间的线加上/删掉 
	}
	modify(u<<1,L,R,add);
	modify(u<<1|1,L,R,add);
	pushup(u);
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++) {
		int x_1,y_1,x_2,y_2;
		cin>>x_1>>y_1>>x_2>>y_2;
		x[2*i-1]=x_1;x[2*i]=x_2;
		l[2*i-1]={x_1,x_2,y_1,1};
		l[2*i]={x_1,x_2,y_2,-1};
	}
	n<<=1;
	sort(x+1,x+n+1);
	sort(l+1,l+n+1);
	int tot=unique(x+1,x+n+1)-x-1;
	build(1,1,tot-1);
	//这里[l,r]表示x[l]-x[r+1]
	//否则在访问单点时长度为x[l]-x[l]=0,显然不对
	//所以tot-1实际到了x[tot]
	int res=0;
	for(int i=1;i<n;i++){
		modify(1,l[i].l,l[i].r,l[i].flag);
		res+=tr[1].len*(l[i+1].h-l[i].h);
	}
	cout<<res;
	return 0;
}

标签:底边,int,线段,扫描线,区间,矩形
From: https://www.cnblogs.com/zxh923aoao/p/18379960

相关文章

  • 扫描线总结
    扫描线是线段树的典型应用。这玩意不难,用途也比较狭窄,重点在理解思想。例0【模板】扫描线题意求\(n\)个四边平行于坐标轴的矩形的面积并。对于\(100\%\)的数据,\(1\len\le{10}^5\),\(0\lex_1<x_2\le{10}^9\),\(0\ley_1<y_2\le{10}^9\)。解析如果用暴力......
  • 刍议线段树 3 (扫描线)
    扫描线扫描线是一种另外的思想,只是其中会运用到线段树以求优化。所以不要将扫描线简单的并为线段树的一个小拓展。例题:https://www.luogu.com.cn/problem/P5490大意:求\(n\)个四边平行于坐标轴的矩形的面积并。思路:纵向分割图形我们考虑把这些纵向矩形分割。那么,总面积就......
  • 扫描线
    Abstract介绍一下扫描线的经典用法。命名空间还挺好用的。A-扫描线(模板)Idea想象现在有一根线正在从左向右扫描,那么,我们就可以通过纵坐标上区间的覆盖情况去确定扫过的矩形覆盖的面积,区间覆盖情况可以用线段树去维护。实现细节见代码注释。Code#include<bits/stdc++.h>#......
  • 扫描线学习笔记
    前言扫描线思想可以在\(O(n^2)\)的时间复杂度内进行二维平面的计算,运用线段树优化可以在\(O(n\logn)\)的时间复杂度内解决。简介P5490【模板】扫描线以此题为例,介绍扫描线。最直接的想法是将每个正方形的面积先加起来,最后再减去重叠部分,但是代码难度较大,不易于实现。......
  • 扫描线学习笔记
    扫描线是一种算法思想,其特征为将静态\(k\)维问题转化为动态\(k-1\)维问题。动态\(k-1\)维问题往往需要数据结构维护。例题【模板】扫描线题意:求矩形面积并,其中每个举行的四边平行于坐标轴。考虑扫描线,将静态\(2\)维问题转化为动态\(1\)维问题。具体的,考虑按\(......
  • 算法随笔——扫描线
    https://www.acwing.com/solution/content/135911/放个模板先P5490【模板】扫描线#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#defineINF0x3f3f3f3f#definereregister#defineintll#definePIIpair<int,int>intread(){ intf=1,k=0......
  • Cesium雷达扫描线效果
    更多精彩内容尽在dt.sim3d.cn,关注公众号【sky的数孪技术】,技术交流、源码下载请添加VX:digital_twin123源码如下:varviewer=newCesium.Viewer("cesiumContainer");varscene=viewer.scene;varmatGLSL="#defineLlength(c-.1*......
  • 扫描线
    扫描线把题目给的的区间想象成平面直角坐标系上的点.再想象一条直线,按顺序扫描获取信息,维护信息求出矩形面积并:把一个矩形看出两条平行于纵轴的边,一条表示加入,一条表示删除,有很多区间的信息是一样的,用乘法处理,扫描线上的信息最多变动\(2n\)次考虑用线段树......
  • [University CodeSprint 4] Drawing Rectangles (扫描线 + 最小点覆盖)
    [UniversityCodeSprint4]DrawingRectangles扫描线+最小点覆盖题目的形式一看就是扫描线,观察到矩形的并面积\(\le3\times10^5\),所以可以直接把这些位置找出来。这部分的复杂度是\(O(n\logn)\)。然后剩下的部分就是一个经典的最小点覆盖问题。具体的说,构造二分图,左边代......
  • HDU 3642 (扫描线、三维体积相交)
    题意在三维空间中给你n个长方体,求空间中被这些长方体覆盖至少3次以上的区域的总体积。思路这题没给数据组数T的范围,大致看了一下其他人的都是枚举z来做的,所以我这边也是同样的做法转换成二维的扫描线来做,数组ci表示被覆盖i次的区间标记,具体扫描线怎么实现可以看我上篇博客。......