其他分享
首页 > 其他分享> > 离散化扫描线

离散化扫描线

作者:互联网

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

标签:个点,int,距离,离散,扫描线,区间,include
来源: https://blog.csdn.net/AC__dream/article/details/122760563