首页 > 其他分享 >扫描线

扫描线

时间:2023-10-27 23:34:15浏览次数:44  
标签:int tr len tag 扫描线 include

假设有一条扫描线从一个图形的下方扫向上方(或者左方扫到右方),那么通过分析扫描线被图形截得的线段就能获得所要的结果。该过程可以用线段树进行加速。
P5490 【模板】扫描线
扫描线可以处理两类问题
一类是面积并
一类是周长并

#include<iostream>
#include<algorithm>
using namespace std;
#define ls u<<1
#define rs u<<1|1
typedef long long ll;
const int N = 2e5+10;
struct line{
	int x1,x2,y;//每一条扫描线的左右端点及其纵坐标
	int tag;//入边为1,出边为-1
	bool operator<(line &t){
		return y<t.y;
	}
}L[N<<1];//每个矩阵会产生两条扫描线
struct tree{
	int l,r;
	ll cnt,len;
	//  cnt: 被完全覆盖的次数;
	//  len: 区间内被截的长度。
}tr[N<<3];
int X[N<<1];
void build(int u,int l,int r){
	tr[u]={l,r,0,0};
	if(l==r)return;
	int mid = (l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
}
void pushup(int u){
	int l=tr[u].l,r=tr[u].r;
	if(tr[u].cnt)//      更新长度
		tr[u].len= X[r+1]-X[l];
	else //      合并儿子信息
		tr[u].len=tr[ls].len+tr[rs].len;
}
void modify(int u,int l,int r,int tag){
	if(l>tr[u].r||r<tr[u].l)return;
	if(l<=tr[u].l&&tr[u].r<=r){
		tr[u].cnt+=tag;
		pushup(u);
		return;
	}
	modify(ls,l,r,tag);
	modify(rs,l,r,tag);
	pushup(u);
}
int x1,x2,y1,y2;
int main(){
	int n;
	scanf("%d",&n);
	
	for(int i=1;i<=n;i++){
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		L[i]={x1,x2,y1,1};
		L[n+i]={x1,x2,y2,-1};
		X[i]=x1,X[n+i]=x2;
	}
	n*=2;
	sort(L+1,L+n+1);
	sort(X+1,X+n+1);
	int tot = unique(X+1,X+n+1)-X-1;//去重 
	//tot为离散化后有多少个节点  
	build(1,1,tot-1);
	ll ans=0;
	for(int i=1;i<n;i++){
		int l = lower_bound(X+1,X+tot+1,L[i].x1)-X;
		int r = lower_bound(X+1,X+tot+1,L[i].x2)-X;
		modify(1,l,r-1,L[i].tag);
		ans+=1ll*tr[1].len*(L[i+1].y-L[i].y);
	}	
	
	printf("%lld",ans);
	return 0;	
} 

注意:变量名y1在库里头有定义,会冲突,所以不开bits库就好。

P1856 [IOI1998] [USACO5.5] 矩形周长Picture

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5+10;
struct Line{
	int l,r,y;
	int tag;//入边:1 ;出边:-1 
	bool operator<(Line &t){
		return y==t.y? tag>t.tag:y<t.y;
	}
}L[N*2];
int X[N*2];
struct tree{
	int l,r;
	int cnt,len;//区间覆盖次数和覆盖长度 
	int sum;//区间覆盖的竖边条数 
	bool lcover,rcover;//左右端点是否被覆盖,用于线段树的区间合并
}tr[N*8];
void build(int u,int l,int r){
	tr[u]={l,r,0,0,0,0,0};
	if(l==r){
		
		return;
	}
	int mid = (l+r)/2;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
}
void pushup(int u){
	int l = tr[u].l,r=tr[u].r;
	if(tr[u].cnt){
		tr[u].len = X[r+1]-X[l];
		tr[u].sum = 2;
		tr[u].lcover = tr[u].rcover = true;
	}
	else{
		tr[u].len = tr[u<<1].len+tr[u<<1|1].len;
		tr[u].sum = tr[u<<1].sum+tr[u<<1|1].sum;
		tr[u].lcover = tr[u<<1].lcover;
		tr[u].rcover = tr[u<<1|1].rcover;
		if(tr[u<<1|1].lcover&&tr[u<<1].rcover)
			tr[u].sum -= 2;//左右区间连续 
	} 
}
void modify(int u,int l,int r,int tag){
	if(l>tr[u].r||tr[u].l>r)return;
	if(l<=tr[u].l&&tr[u].r<=r){
		tr[u].cnt+=tag;
		pushup(u);
		return;
	}
	
	modify(u<<1,l,r,tag);
	modify(u<<1|1,l,r,tag);
	pushup(u);
}
int x1,x2,y1,y2,pre;
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		X[i] = x1;X[i+n] = x2;
		L[i]={x1,x2,y1,1};
		L[n+i]={x1,x2,y2,-1};
	}
	n*=2;
	sort(L+1,L+n+1);
	sort(X+1,X+n+1);
	int tot = unique(X+1,X+n+1)-X-1;//统计可以离散化为多少个点
	int res = 0;
	build(1,1,tot-1);
	for(int i=1;i<n;i++){
		int l = lower_bound(X+1,X+tot+1,L[i].l)-X;
		int r = lower_bound(X+1,X+tot+1,L[i].r)-X;
		
		modify(1,l,r-1,L[i].tag);
		res+=abs(tr[1].len-pre);//计算横边 
		pre=tr[1].len;
		res+=tr[1].sum*(L[i+1].y-L[i].y);//计算竖边 
	}
	res+=L[n].r-L[n].l;//加上最后一条扫描线的长度。
	printf("%d",res);
	return 0; 
} 

标签:int,tr,len,tag,扫描线,include
From: https://www.cnblogs.com/2002cjc/p/17793357.html

相关文章

  • Auguryの扫描线分享
    Auguryの扫描线分享扫描线是啥有时候答案是不好计算的,但是答案可以拆分成多个段分别计算,且段与段之间可以快速转换,我们就可以用扫描线解决。或者说,一个二维问题,我们可以用扫描线变成一维。前置芝士线段树、值域线段树、树状数组(胡扬好闪,拜谢胡扬)离散化现在我们有一堆数,你......
  • 写个扫描线吧
    虽然扫描线很简单,但是我发现理解还是有些不清晰,于是决定写一篇。原问题,或者说是例题一个不好暴力东西,暴力模拟不带优化至少O(n^3)也是一个非常经典的线段树例题(因为懒得画图所以下面就直接用网上dalao的题解里面的图片了)首先,因为我们要在线段树上面记录下来每一个起始点和结束点,所......
  • 扫描线
    #include<bits/stdc++.h>#definemaxn200005#defineintlonglongusingnamespacestd;intx[maxn];//x[i]表示从左往右第i条竖边inttsum[maxn<<3],tlen[maxn<<3];//tsum表示当前节点被覆盖的次数//tlen是当前节点所对应的长方形的长voidpushup(intk,intl,intr)/......
  • 扫描线补充
    1.两条扫描线之间,不一定是一个矩形,可能是多个不相交的,高相同的矩形2.扫描线的板子没有pushdownvoidupd(intu,intl,intr){ if(cnt[u]){ len[u]=b[r+1]-b[l]; sum[u]=2; lh[u]=rh[u]=1; }else{ len[u]=len[lch]+len[rch]; sum[u]=sum[lch]+sum[rch]; lh[u]=lh[......
  • P5490 【模板】扫描线
    \(P5490\)【模板】扫描线一、题目描述求\(n\)个四边平行于坐标轴的矩形的面积并。输入格式第一行一个正整数\(n\)。接下来\(n\)行每行四个非负整数\(x_1,y_1,x_2,y_2\),表示一个矩形的四个端点坐标为\((x_1,y_1),(x_1,y_2),(x_2,y_2),(x_2,y_1)\)。输出格式......
  • 【单调队列】 单调队列的“扫描线”理解
    【单调队列】单调队列的“扫描线”理解  “如果一个选手比你小还比你强,你就可以退役了。”——单调队列的原理比你强,而且比你影响时间更长。某种意义上,数学思维是生活中的思考的延伸。  算法学习笔记(66):单调队列。引用Pecco的算法笔记。  在这里给出一种扫描线......
  • 扫描线学习笔记
    0.写在前面扫描线好闪,拜谢扫描线1.问题的引入在一个二维的坐标系上,给出多个矩形,求他们的面积并2.问题的分析假设我们有这么一张图你要求这三个矩形的面积并,可以考虑容斥原理,但这样会TLE但总之,他最终的结果是围成了一个多边形那你不妨考虑,重新分割这个最终的图形那......
  • 「学习笔记」扫描线
    什么是扫描线?顾名思义,一根用来扫描的线扫描线就是一条线在整个图上扫来扫去,它一般被用来解决图形面积,周长,以及二维数点等问题。下面我们用例题来引入。P5490【模板】扫描线-洛谷|计算机科学教育新生态(luogu.com.cn)我们对于这种题有三种做法暴力的进行覆盖扫描容......
  • [Ynoi2012] NOIP2015 充满了希望(扫描线+线段树)
    题目传送门solution简单题。我们正着做扫描线。设\(t_i\)表示位置\(i\)最后一次进行二操作的时间,那么一操作就是交换\(t_x,t_y\),二操作就是区间复制。对于三操作,开一个树状数组,如果查询的位置的\(t_x=j\),就在\(j\)的位置上加一。查询就是查询后缀和。#include<bit......
  • [Ynoi Easy Round 2021] TEST_152(颜色段数均摊+扫描线)
    题目传送门solution简单题,考虑正着做扫描线,维护最后一次覆盖每个位置的修改时间,这个可以用\(set\)维护颜色段数均摊。那么显然对于一个以当前位置为右端点的询问,其答案就是所有最后修改时间大于等于左端点的位置的数的和。开一个树状数组维护最后一次修改时间是\(i\)的位......