P5490 【模板】扫描线

题目地址


注意点:

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

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=2e6;
struct Line{
	ll x1,x2,y;
	bool type;
	bool operator <(Line another)const{
		return y<another.y;
	}
}lines[MAXN];
int lineCnt=0;
struct Node{
	int l,r;
	ll len,cnt;
}tr[MAXN];
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];//离散化 
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++){
		ll x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		lines[++lineCnt].x1=x1,lines[lineCnt].x2=x2;
		lines[lineCnt].y=y1,lines[lineCnt].type=0;
		lines[++lineCnt].x1=x1,lines[lineCnt].x2=x2;
		lines[lineCnt].y=y2,lines[lineCnt].type=1;
		a[i]=x1,a[i+n]=x2;
	}
	sort(a+1,a+2*n+1);
	int cnt=unique(a+1,a+2*n+1)-a-1;//离散化
	sort(lines+1,lines+2*n+1);
	build(1,1,cnt-1);
	ll ans=0;
	for(int i=1;i<=2*n;i++){
		Line nowLine=lines[i];
		if(i>1)ans+=tr[1].len*(lines[i].y-lines[i-1].y);
		if(nowLine.type){//消失 
			change(1,lower_bound(a+1,a+cnt+1,nowLine.x1)-a,lower_bound(a+1,a+cnt+1,nowLine.x2)-a-1,-1);
		}else{//出现 
			change(1,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