扫描线暴力解决的话时间和空间复杂度往往是不够的。

所以,扫描线也就成了线段树很大的应用。


给出模板:第一篇博客(饶齐大佬)的修正与改进,还有一些地方的解释,错误原因

第一个:

我们在线段树更新的时候,是这样往下走的:    
sumv[O]=sumv[O*2]+sumv[O*2+1].
如果左子树维护的区间[l,mid],
右子树维护的区间[mid+1,r]
那么还有一个区间[mid,mid+1]没有统计到,怎么办?
下面代码解释是左闭右开,请读者自行思考。

//二维平面有n个平行于坐标轴的矩形,现在要求出这些矩形的总面积. 重叠部分只能算一次.
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2222;
#define lson i<<1,l,m
#define rson i<<1|1,m+1,r
#define root 1,1,k-1
double X[MAXN];
struct node
{
double l,r,h;
int d; ///d为1或-1,标记扫描线是矩形的上位还是下位边.
node(){}
node(double a,double b,double c,int d): l(a),r(b),h(c),d(d){}
bool operator <(const node &b)const
{
return h<b.h;
}
}nodes[MAXN];
///cnt: >=0时表示本节点控制的区域内下位边个数-上位边个数的结果.
///如果==-1时,表示本节点左右子树的上下位边数不一致.
///sum: 本节点控制的区域内cnt值不为0的区域总长度.
int cnt[MAXN*4];
double sum[MAXN*4];
///如果cnt!=-1,那么下放cnt信息,并更新子节点的sum信息.
void PushDown(int i,int l,int r)
{
int m=(l+r)>>1;
if(cnt[i]!=-1)
{
cnt[i<<1]=cnt[i<<1|1]=cnt[i];
sum[i<<1]= (cnt[i]?(X[m+1]-X[l]):0) ;
sum[i<<1|1]= (cnt[i]?(X[r+1]-X[m+1]):0) ;
}
}
///根据子节点的cnt值和sum值更新父节点的cnt和sum值
void PushUp(int i,int l,int r)
{
if(cnt[i<<1]==-1 || cnt[i<<1|1]==-1)
cnt[i]=-1;
else if(cnt[i<<1] != cnt[i<<1|1])
cnt[i]=-1;
else
cnt[i]=cnt[i<<1];
sum[i]=sum[i<<1]+sum[i<<1|1];
}

void update(int ql,int qr,int v,int i,int l,int r)
{
if(ql<=l && r<=qr)
{
if(cnt[i]!=-1)
{
cnt[i]+=v;
sum[i] = (cnt[i]? (X[r+1]-X[l]):0);
return ;
}
}
PushDown(i,l,r);
int m=(l+r)>>1;
if(ql<=m) update(ql,qr,v,lson);
if(m<qr) update(ql,qr,v,rson);
PushUp(i,l,r);
}
///二分寻找区间 ,每一个扫描线
int bin(double key,int n,double d[])
{
int l=1,r=n;
while(r>=l)
{
int m=(r+l)>>1;
if(d[m]==key)
return m;
else if(d[m]>key)
r=m-1;
else
l=m+1;
}
return -1;
}
int main()
{
int q;
int kase=0;
while(scanf("%d",&q)==1&&q)
{
int n=0,m=0;
for(int i=1;i<=q;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
X[++n]=x1;
nodes[++m]=node(x1,x2,y1,1);
X[++n]=x2;
nodes[++m]=node(x1,x2,y2,-1);
}
sort(X+1,X+n+1);
sort(nodes+1,nodes+m+1);
int k=unique(X+1,X+n+1)-(X+1);//去掉相邻的重复元素
//build(1,1,k-1);
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
double ret=0.0;//最终面积
for(int i=1;i<m;i++)
{
int l=bin(nodes[i].l,k,X);
int r=bin(nodes[i].r,k,X)-1;///左开右闭的性质
//cout<<l<<" "<<r<<endl;
if(l<=r) update(l,r,nodes[i].d,root);
ret += sum[1]*(nodes[i+1].h-nodes[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ret );
}
}

经典例题:

​​HDU 1542 Atlantis(线段树:扫描线)​​