线段树-扫描线

这其实是计算几何的一部分。一般被用来解决图形面积、周长等问题。

Atlantis 问题(板题)

题意

求给定的 \(n\) 个矩形的面积并

解法

如图:

  • 每一块颜色不同的部分都是一个矩形,这 \(n\) 个矩形的面积并就是重新划分后各个颜色的矩形的面积和

  • 扫过的距离 乘 当前的宽度就是当前矩形的面积


(从左到右扫)

若一个矩形的左下顶点坐标为 \((x_1,y_1)\) ,右上顶点坐标为 \((x_2,y_2)\)

  • 将它的左沿和右沿两条边存成一个四元组;左:\((x_1,y_1,y_2,1)\),右:\((x_2,y_1,y_2)\) 。最后的标记:\(1\) 表示加入这条边;\(-1\) 表示减去这条边

  • \(n\) 个矩形都这样做处理,就得到 \(2n\) 条边,把这 \(2n\) 条边按照 \(x\) 的大小从小到大排序

  • 因为数据可能很大而且不一定是整数,所以要对 \(y\) 进行 离散化 处理


模板代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

const int N=1e5+5;
int n;
double ls[N<<1]; 
struct line{
	int x,y1,y2,mrk;
}a[N<<4];
struct node{
	int l,r,sum,len;//sum:被完全覆盖的次数 ; len:被选取的长度 
}tr[N<<4];

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

void build(int node,int l,int r){
	tr[node].l=l,tr[node].r=r;
	tr[node].len=0;
	tr[node].sum=0;
	if(l==r)
		return;
	
	int mid=(l+r)>>1;
	build(node<<1,l,mid);
	build(node<<1|1,mid+1,r);
	return;
}

void pushup(int node){
	int l=tr[node].l,r=tr[node].r;
	if(tr[node].sum)
		tr[node].len=ls[r+1]-ls[l];
	else
		tr[node].len=tr[node<<1].len+tr[node<<1|1].len;
}

void change(int node,int l,int r,int x){
	int L=tr[node].l,R=tr[node].r;//L,R与l,r 意义完全不同
	if(ls[R+1]<=l || ls[L]>=r)//R+1才能覆盖完区间 
		return;
	if(l<=ls[L] && r>=ls[R+1]){
		tr[node].sum+=x;
		pushup(node);
		return;
	}
	
	change(node<<1,l,r,x);
	change(node<<1|1,l,r,x);
	pushup(node);
}

signed main(){
	
	cin>>n;
	for(int i=1;i<=n;++i){
		int x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		a[i*2-1].x=x1,a[i*2-1].y1=y1,a[i*2-1].y2=y2;
		a[i*2].x=x2,a[i*2].y1=y1,a[i*2].y2=y2;
		a[i*2-1].mrk=1,a[i*2].mrk=-1;
		ls[i*2-1]=y1,ls[i*2]=y2;
	}
	
	n<<=1;//后面用起来方便
	sort(a+1,a+n+1,cmp);
	sort(ls+1,ls+n+1);//离散化 
	
	int tot=unique(ls+1,ls+n+1)-ls-1;//去重 
	ls[tot+1]=0x3f3f3f3f;
	build(1,1,tot);//建树 
	
	int ans=0;
	for(int i=1;i<n;++i){
		change(1,a[i].y1,a[i].y2,a[i].mrk);
		ans+=tr[1].len*(a[i+1].x-a[i].x);
	}
	
	cout<<ans;
	
	return 0;
}

拓展题目

求周长

posted @ 2022-02-15 14:40  _yolanda  阅读(48)  评论(0编辑  收藏  举报