P5490 【模板】扫描线

时间:2019-10-26
本文章向大家介绍P5490 【模板】扫描线,主要包括P5490 【模板】扫描线使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目地址


注意点:

  • 线段树中使用获取具体长度时右端点应当+1,向线段树内插入值时右端点应当-1.(区间覆盖线段树)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=2e6+50;
struct Line{
	ll x1,x2;
	ll y;
	bool type;//0:出现 1:删除 
	bool operator <(Line another)const{
		return y<another.y;
	}
}lines[MAXN];
int lineCnt=0;
void addLine(ll x1,ll x2,ll y,bool type){
	lines[++lineCnt].x1=x1;
	lines[lineCnt].x2=x2;
	lines[lineCnt].y=y;
	lines[lineCnt].type=type;
}
struct Node{
	int l,r;
	ll len,cnt;//长度 覆盖次数 
}tr[MAXN*4];
int root=1;
void build(int p,int l,int r){
	tr[p].l=l,tr[p].r=r;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build((p<<1)|1,mid+1,r);
}
ll a[MAXN];//离散化后的x坐标 
void pushup(int p){
	if(tr[p].cnt){
		tr[p].len=a[tr[p].r+1]-a[tr[p].l];
	}else{
		tr[p].len=tr[p<<1].len+tr[(p<<1)|1].len;
	}
}
void change(int p,int l,int r,int val){
	if(tr[p].l>=l&&tr[p].r<=r){
		tr[p].cnt+=val;
		pushup(p);
		return;
	}
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid)change(p<<1,l,r,val);
	if(r>mid)change((p<<1)|1,l,r,val);
	pushup(p);
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		a[i]=x1,a[i+n]=x2;
		addLine(x1,x2,y1,0);
		addLine(x1,x2,y2,1);
	}
	sort(a+1,a+2*n+1);
	int cnt=unique(a+1,a+2*n+1)-a-1;//离散化 
	build(root,1,cnt-1);
	sort(lines+1,lines+lineCnt+1);
	ll ans=0;
	for(int i=1;i<=lineCnt;i++){
		Line nowLine=lines[i];
		if(i>1){
			ans+=tr[root].len*(nowLine.y-lines[i-1].y);
		}
		if(nowLine.type==0){//增加
			change(root,lower_bound(a+1,a+cnt+1,nowLine.x1)-a,lower_bound(a+1,a+cnt+1,nowLine.x2)-a-1,1);
		}else if(nowLine.type==1){//减少 
			change(root,lower_bound(a+1,a+cnt+1,nowLine.x1)-a,lower_bound(a+1,a+cnt+1,nowLine.x2)-a-1,-1);
		}
	}
	cout<<ans<<endl;
	return 0;
}

  

原文地址:https://www.cnblogs.com/zbsy-wwx/p/11745561.html