线段树扫描线模板及感悟
扫描线问题算是一个线段树问题的简单变种。模型是在一个平面内给n个有重叠部分的矩形,求其覆盖的面积。思路是将矩形的上下边界看作扫描线,同时离散化x坐标用线段树维护,维护的是离散后的每个区间不是离散后的点,是(n-1)个!!!!!
维护两个值,一个是cnt即覆盖在其上方的矩阵数量(可通过扫描线是矩形的上边界还是下边界,从而+1/-1来判断),另一个是sum即每个区间内被覆盖的长度。而每次增加的面积就是sum[1]乘以两条扫描线之间的高度差。
需要注意的是,因为我们每次只需要的是sum[1],不需要其子节点的值,所以我们不需要标记下放,不需要lazy,只需要一个pushup函数,更新每个节点的sum
void pushup(int k,int l,int r)
{
if(con[k])
sum[k]=X[r+1]-X[l];
else
sum[k]=sum[k*2]+sum[k*2+1];
}
后附模板代码:
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define MAXN 4000005
using namespace std;
inline ll re()
{
char f=getchar();
ll k=1,x=0;
while(f>'9'||f<'0')
{
if(f=='-') k=-1;
f=getchar();
}
while(f>='0'&&f<='9')
{
x=x*10+f-'0';
f=getchar();
}
return x*k;
}
struct a1{
int l,r,h,d;
};
a1 lin[MAXN];
bool cmp(a1 x,a1 y)
{
return x.h<y.h;
}
int tot,cnt;
int n,X[MAXN],con[MAXN],sum[MAXN];
void pushup(int k,int l,int r)
{
if(con[k])
sum[k]=X[r+1]-X[l];
else
sum[k]=sum[k*2]+sum[k*2+1];
}
void change(int k,int l,int r,int al,int ar,int c)
{
if(l>ar||r<al) return;
if(l>=al&&r<=ar)
{
con[k]+=c;
pushup(k,l,r);
return;
}
int mid=l+r>>1;
change(k*2,l,mid,al,ar,c);
change(k*2+1,mid+1,r,al,ar,c);
pushup(k,l,r);
}
signed main()
{
n=re();
for(int i=1;i<=n;i++)
{
int x11=re(),y11=re(),x22=re(),y22=re();
lin[++tot].l=x11,lin[tot].r=x22;
lin[tot].h=y11,lin[tot].d=1;
X[tot]=x11;
lin[++tot].l=x11,lin[tot].r=x22;
lin[tot].h=y22,lin[tot].d=-1;
X[tot]=x22;
}
sort(X+1,X+tot+1);
cnt=unique(X+1,X+tot+1)-(X+1);
sort(lin+1,lin+tot+1,cmp);
ll ans=0;
for(int i=1;i<tot;i++)
{
int LL=lower_bound(X+1,X+cnt+1,lin[i].l)-X;
int RR=lower_bound(X+1,X+cnt+1,lin[i].r)-X;
RR--;
if(LL<=RR) change(1,1,cnt-1,LL,RR,lin[i].d);
ans+=sum[1]*(lin[i+1].h-lin[i].h);
}
cout<<ans;
}