线段树扫描线模板及感悟

线段树扫描线模板及感悟

扫描线问题算是一个线段树问题的简单变种。模型是在一个平面内给n个有重叠部分的矩形,求其覆盖的面积。思路是将矩形的上下边界看作扫描线,同时离散化x坐标用线段树维护,维护的是离散后的每个区间不是离散后的点,是(n-1)个!!!!!

维护两个值,一个是cnt即覆盖在其上方的矩阵数量(可通过扫描线是矩形的上边界还是下边界,从而+1/-1来判断),另一个是sum即每个区间内被覆盖的长度。而每次增加的面积就是sum[1]乘以两条扫描线之间的高度差。

需要注意的是,因为我们每次只需要的是sum[1],不需要其子节点的值,所以我们不需要标记下放,不需要lazy,只需要一个pushup函数,更新每个节点的sum

void pushup(int k,int l,int r)
{
	if(con[k])
		sum[k]=X[r+1]-X[l];
	else 
		sum[k]=sum[k*2]+sum[k*2+1];
}

后附模板代码:

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define MAXN 4000005
using namespace std;
inline ll re()
{
	char f=getchar();
	ll k=1,x=0;
	while(f>'9'||f<'0')
	{
		if(f=='-') k=-1;
		f=getchar();
	}
	while(f>='0'&&f<='9')
	{
		x=x*10+f-'0';
		f=getchar();
	}
	return x*k;
}

struct a1{
	int l,r,h,d;
};
a1 lin[MAXN];
bool cmp(a1 x,a1 y)
{
	return x.h<y.h;
}
int tot,cnt;
int n,X[MAXN],con[MAXN],sum[MAXN];
void pushup(int k,int l,int r)
{
	if(con[k])
		sum[k]=X[r+1]-X[l];
	else 
		sum[k]=sum[k*2]+sum[k*2+1];
}
void change(int k,int l,int r,int al,int ar,int c)
{
	if(l>ar||r<al)	return;
	if(l>=al&&r<=ar)
	{
		 con[k]+=c;
		 pushup(k,l,r);
		 return;
	} 
	int mid=l+r>>1;
	change(k*2,l,mid,al,ar,c);
	change(k*2+1,mid+1,r,al,ar,c);
	pushup(k,l,r);
}
signed main()
{
	n=re();
	for(int i=1;i<=n;i++)
	{
		int x11=re(),y11=re(),x22=re(),y22=re();
		lin[++tot].l=x11,lin[tot].r=x22;
		lin[tot].h=y11,lin[tot].d=1;
		X[tot]=x11;
		lin[++tot].l=x11,lin[tot].r=x22;
		lin[tot].h=y22,lin[tot].d=-1;
		X[tot]=x22;
	}
	
	sort(X+1,X+tot+1);
	cnt=unique(X+1,X+tot+1)-(X+1);
	sort(lin+1,lin+tot+1,cmp);
	
	ll ans=0;
	for(int i=1;i<tot;i++)
	{
		int LL=lower_bound(X+1,X+cnt+1,lin[i].l)-X;
		int RR=lower_bound(X+1,X+cnt+1,lin[i].r)-X;
		RR--; 
		if(LL<=RR) change(1,1,cnt-1,LL,RR,lin[i].d);
		ans+=sum[1]*(lin[i+1].h-lin[i].h);
	}
	
	cout<<ans;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值