离散化扫描线

 这是一道需要离散化后的扫描线模板题,但是这道题有一个细节非常重要,所以拿出来单独说一下,扫描线的基本实现原理我就不赘述了,如果还有不明白的小伙伴可以看下我之前的介绍扫描线的博客,下面是地址:油漆面积(扫描线)_AC__dream的博客-CSDN博客

这两道题最大的区别就是这道题目的数据范围是1e9,显然不能直接建立这么大的线段树,需要我们先对给出的数据进行离散化,然后再按照正常的扫描线来进行处理

但是大家有没有发现扫描线要求我们维护的是线段,而不是一般的点,就比如我们离散化后的点一共有4个,假如我们对区间[1,3]进行修改,那么最后应该是对[1,2]和[3,3]两个区间分别进行修改,但是大家有没有发现一个问题,如果说区间[1,2]表示第1和2两个点的距离,那么区间[3,3]表示的岂不是3和3两个点的距离了?那这样满足左右端点相同的区间的距离岂不是一直是0了?况且我们永远处理不到2和3的距离,所以这样一定是会错的,那应该怎么办呢?如果说我们令线段树区间[l,r]表示的是第l个点和r+1个点之间的距离的话,那么任何一个区间都能够被表示了。而这恰恰是我在油漆面积那道题中忘记说明的非常重要的一点,因为拿到题目没有离散化,所以直接每两个相邻点之间的距离就是1,因为线段树区间[l,r]表示的是第l个点和第r+1个点之间的距离,所以距离就是(r+1)-l。

下面是这道题目的代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
#define int long long
const int N=1e6+10;
int l[N],r[N],cnt[N],len[N];
vector<int>alls;
int find(int x)
{
	return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
struct edge{
	int x,yn,yx,k;
}p[N];
bool cmp(edge a,edge b)
{
	return a.x<b.x;
}
void pushup(int id)
{
	if(cnt[id])	 len[id]=alls[r[id]]-alls[l[id]-1];//点区间[l[id],r[id]]实际表示的是线段区间[alls[l[id]-1],alls[r[id]]] 
	else if(l[id]==r[id]) len[id]=0;
	else len[id]=len[id<<1]+len[id<<1|1];
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;cnt[id]=len[id]=0;
	if(L==R) return ;
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
}
void update_interval(int id,int L,int R,int k)
{
	if(l[id]>=L&&r[id]<=R)//当前区间完全在目标区间中 
	{
		cnt[id]+=k;
		pushup(id);
		return ;
	}
	int mid=l[id]+r[id]>>1;
	if(mid>=L) update_interval(id<<1,L,R,k);
	if(mid+1<=R) update_interval(id<<1|1,L,R,k);
	pushup(id);
}
signed main()
{
	int n;
	cin>>n;
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
		alls.push_back(y1);alls.push_back(y2);;
		p[++cnt]={x1,y1,y2,1};
		p[++cnt]={x2,y1,y2,-1};
	}
	sort(p+1,p+cnt+1,cmp);
	sort(alls.begin(),alls.end());
	alls.erase(unique(alls.begin(),alls.end()),alls.end());
	for(int i=1;i<=cnt;i++)
	{
		p[i].yn=find(p[i].yn);
		p[i].yx=find(p[i].yx);
	}
	build(1,1,alls.size());
	long long ans=0;	
	for(int i=1;i<=cnt;i++)
	{
		if(i>1) ans+=(p[i].x-p[i-1].x)*len[1];
		update_interval(1,p[i].yn,p[i].yx-1,p[i].k);
	}
	printf("%lld",ans);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值