【模板】扫描线

洛咕

题意:求(n)个矩形的面积并.

分析:扫描线的模板题.想象有一根竖直的线从左往右扫过去,那么矩形面积发生变化的时刻只可能是到达了某个矩形的左边界或者右边界.所以设一个矩形的左下角坐标为(x_1,y_1),右上角坐标为(x_2,y_2),则该矩形可以表示为两个四元组((x_1,y_1,y_2,1))((x_2,y_1,y_2,-1)),相当于是两根线段,其中第四维(1)表示左边界,(-1)表示右边界.

按照(x)从小到大扫描这(2*n)根线段,那么每碰到一根线段((x,y_1,y_2,z)),把区间([y_1,y_2])都加上(z),那么统计答案的时候如果这一段区间的值大于(0),表示当前它产生了贡献,然后再乘上这根线段与下一根线段之间的(x)距离(即矩形宽度),就是这一个小矩形的贡献了.

然后注意到有个区间增加操作,所以可以用线段树来维护,从而时间复杂度(n^2)优化到(nlogn).

本题中(y)坐标很大,插入线段树前需要离散化,又因为统计答案的时候需要知道具体的坐标值,所以离散化的时候还要映射回去.

本题(20)分是因为数组开小了(如果写法不优秀,数组不能只开(4)倍),具体原因见本题讨论区.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=1e6+5;
int n,tot,a[N],raw[N],cnt[N<<2],sum[N<<2];
struct node{int x,y1,y2,z;}e[N];
inline bool cmp(node x,node y){return x.x==y.x?x.y1<y.y1:x.x<y.x;}
inline void change(int p,int l,int r,int ql,int qr,int val){
	if(ql<=l&&qr>=r){
		cnt[p]+=val;
		if(cnt[p]>0)sum[p]=raw[r+1]-raw[l];
		else sum[p]=sum[p<<1]+sum[p<<1|1];
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid)change(p<<1,l,mid,ql,qr,val);
	if(qr>mid)change(p<<1|1,mid+1,r,ql,qr,val);
	if(cnt[p]>0)sum[p]=raw[r+1]-raw[l];
	else sum[p]=sum[p<<1]+sum[p<<1|1];
}
int main(){
	n=read();
	for(int i=1;i<=n;++i){
		int x1=read(),y1=read(),x2=read(),y2=read(),k1=(i<<1)-1,k2=i<<1;
		e[k1].x=x1;e[k1].y1=y1;e[k1].y2=y2;e[k1].z=1;
		e[k2].x=x2;e[k2].y1=y1;e[k2].y2=y2;e[k2].z=-1;
		a[++tot]=y1;a[++tot]=y2;
	}
	sort(a+1,a+tot+1);int len=unique(a+1,a+tot+1)-a-1;n<<=1;
	for(int i=1;i<=n;i+=2){
		int pos1=lower_bound(a+1,a+len+1,e[i].y1)-a;
		int pos2=lower_bound(a+1,a+len+1,e[i].y2)-a;
		raw[pos1]=e[i].y1;raw[pos2]=e[i].y2;
		e[i].y1=e[i+1].y1=pos1;e[i].y2=e[i+1].y2=pos2;
	}
	sort(e+1,e+n+1,cmp);ll ans=0;
	for(int i=1;i<=n;++i){
		change(1,1,n,e[i].y1,e[i].y2-1,e[i].z);
		ans+=1ll*(e[i+1].x-e[i].x)*sum[1];
	}
	printf("%lld
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11862842.html