LGP5490 [LG TPLT] 矩形面积并 学习笔记
LGP5490 [LG TPLT] 矩形面积并 学习笔记
前言
有时候回顾一下过往的代码还是有好处的。既提醒我了关于扫描线的另一种写法,也提醒我了2023年国赛的签到还没做。
另:翻新这个代码的时候一遍过了。爽。
题意简述
求 \(n\) 个四边平行于坐标轴的矩形的面积并。
\(n\le 10^5\),\(0\le x_i,y_i\le 10^9\)。
做法解析
先把坐标离散化。
我们可以无限延长所有矩形的横边。这样整个平面就按 \(y\) 坐标被割成了若干部分。显然我们的答案就是每个部分的高度乘上其中完全被矩形覆盖的长度。
我们用线段树维护矩形的覆盖。具体地,我们又按矩形的左右两个 \(x\) 坐标将 \(x\) 轴割成若干段。在任意时段每一段内部的覆盖状况显然相同。我们的线段树维护两个量:cov是一段 \(x\) 坐标被完全覆盖的次数,flen为线段树结点管辖的这个区间里总共被覆盖的长度。cov大于 \(0\) 时flen即取整个区间的(离散化前的)长度,否则由儿子的flen相加。
因为cov会即刻影响flen所以修改的同时也要pushup。又因为叶子节点也会需要pushup所以特判一下叶子节点。(所以这题的pushup看起来会很特殊)
另外 \(k\) 个 \(x\) 坐标会截出 \(k-1\) 个区间,代码里面有些形如xcnt-1的东西就是这么来的。
代码实现
记住S[i].rx=lwberi(Xs,xcnt,S[i].rx)-1;的这个-1!
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N,X1,Y1,X2,Y2,Xs[MaxN<<1],xcnt;
struct anob{int lx,rx,y,w;}S[MaxN<<1];
bool cmpy(anob a,anob b){return a.y<b.y;}
struct SegTree{
int cov[MaxN<<3],flen[MaxN<<3];
int ls(int u){return u<<1;}
int rs(int u){return (u<<1)|1;}
void pushup(int u,int cl,int cr){
if(cov[u]){flen[u]=Xs[cr+1]-Xs[cl];return;}
flen[u]=(cl==cr?0:flen[ls(u)]+flen[rs(u)]);
}
void update(int u,int cl,int cr,int dl,int dr,int x){
if(dl<=cl&&cr<=dr){cov[u]+=x,pushup(u,cl,cr);return;}
int cmid=(cl+cr)>>1;
if(dl<=cmid)update(ls(u),cl,cmid,dl,dr,x);
if(dr>cmid)update(rs(u),cmid+1,cr,dl,dr,x);
pushup(u,cl,cr);
}
}SgT;
lolo ans;
int main(){
readi(N);
for(int i=1;i<=N;i++){
readis(X1,Y1,X2,Y2);
S[(i<<1)-1]={X1,X2,Y1,1},S[i<<1]={X1,X2,Y2,-1};
Xs[(i<<1)-1]=X1,Xs[i<<1]=X2;
}
sort(S+1,S+(N<<1)+1,cmpy);
sort(Xs+1,Xs+(N<<1)+1),xcnt=unique(Xs+1,Xs+(N<<1)+1)-(Xs+1);
for(int i=1;i<=(N<<1);i++)S[i].lx=lwberi(Xs,xcnt,S[i].lx),S[i].rx=lwberi(Xs,xcnt,S[i].rx)-1;
for(int i=1;i<=(N<<1);i++){
auto [lx,rx,y,w]=S[i];
SgT.update(1,1,xcnt-1,lx,rx,w);
ans+=1ll*SgT.flen[1]*(S[i+1].y-S[i].y);
}
writil(ans);
return 0;
}
浙公网安备 33010602011771号