扫描线.面积

https://www.luogu.com.cn/problem/P5490

对于一个不规则图形我们可以用割补法计算它的面积

而扫描线便是"割"

 把一个不规则图形分成多个四边形(不同颜色)然后底乘高,没了

我们可以用一个结构体把每条红线(扫描线)存下来

struct L{//扫描线 
	long long l,r,h,mark;
}line[11451419]; 

l,r为左右端点,h为纵坐标,mark是一个1/-1的标记便于之后判断是否重叠被覆盖,把它当作不下传的懒标记就行

再把每个端点的横坐标存下来(略)

我们可以把每一段线存入一颗线段树里,计算面积就乘line[i+1].h-line[i].h

 其中13 15 8 9 5均被覆盖所以他们长度计算便是x[r+1]-x[l],其他线段就直接子树相加即可

P5490 【模板】扫描线

code:

#include<bits/stdc++.h>
using namespace std;
long long x[11451419];//扫描到的每个点(的横坐标)
struct L{//扫描线 
	long long l,r,h,mark;
}line[11451419]; 
bool cmp(L a,L b){return a.h<b.h;}
struct T{
	long long l,r,sum,len;
}tree[11451419]; 
void pushup(long long xx){
	long long l=tree[xx].l,r=tree[xx].r;
	if(tree[xx].sum)
	tree[xx].len=x[r+1]-x[l];//被覆盖,就求被覆盖长度 
	else 
	tree[xx].len=tree[xx*2].len+tree[xx*2+1].len;//否则为两个子树之和 
}
void build(long long x,long long l,long long r){
	tree[x]=(T){l,r,0,0};
	if(l==r)return;
	int m=(l+r)/2;
	build(x*2,l,m);
	build(x*2+1,m+1,r);
	return;
}
void updata(long long xx,long long L,long long R,long long c){
	long long l=tree[xx].l,r=tree[xx].r;
	if(x[r+1]<=L||R<=x[l])return;
	if(L<=x[l]&&x[r+1]<=R){
		tree[xx].sum+=c;
		pushup(xx);
		return;
	}
	updata(xx*2,L,R,c);
	updata(xx*2+1,L,R,c);
	pushup(xx);	
}
int main(){
	long long n;
	cin>>n;
	for(long long i=1;i<=n;i++){
		long long x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;
		x[i*2-1]=x1,x[i*2]=x2;
		line[i*2-1]=(L){x1,x2,y1,1};
		line[i*2]=(L){x1,x2,y2,-1};
	}
	n*=2;
	sort(line+1,line+1+n,cmp);
	sort(x+1,x+1+n);
	long long tot=unique(x+1,x+1+n)-(x+1);//我要离散化有何用....STL大好 
	build(1,1,tot-1);
	long long ans=0;
	for(long long i=1;i<n;i++){
		updata(1,line[i].l,line[i].r,line[i].mark);
		ans+=tree[1].len*(line[i+1].h-line[i].h);
	}
	cout<<ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱游戏啊啊啊啊啊啊

爸爸您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值