线段树扫描线

线段树扫描线,矩形面积并,面积的求法模拟扫描线从下向上扫过图形,并快速计算当前扫描线被截得的长度。将横边赋上不同的权值,下边为1,上边为-1。所有横边按照y坐标生序排序,每次先碰到下边,再碰到上边。

矩形周长并,纵边总长度=sum(2被截的线段条数扫过的高度),横边总长度=sum(|上次截得的总长-现在截得的总长|)。

struct SegmentTreeScanLine{
struct tree{
int l,r,cnt/*被完全覆盖的次数*/,len/*区间内被截的长度*/,v/*区间内的线段条数*/;
bool ls,rs;/*表示左右端点是否被覆盖*/
}t[N<<2];
struct scanline{
int l,r,h,f;
inline bool friend operator<(const scanline&a,const scanline&b){
return a.h==b.h?a.f>b.f:a.h<b.h;
}
}line[N<<1];
int val[N<<1];/*对横坐标离散化*/
#define lc (p<<1)
#define rc (p<<1|1)
#define l(p) (t[p].l)
#define r(p) (t[p].r)
#define c(p) (t[p].cnt)
#define le(p) (t[p].len)
#define v(p) (t[p].v)
#define ls(p) (t[p].ls)
#define rs(p) (t[p].rs)
void build(int p,int l,int r){
t[p]={l,r};
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
inline void pushup(int p){
if(c(p)){/*被覆盖过*/
le(p)=val[r(p)+1]-val[l(p)];/*上界-下界*/
ls(p)=rs(p)=1;/*完全覆盖标记*/
v(p)=1;
}
else{
le(p)=le(lc)+le(rc);/*合并长度*/
ls(p)=ls(lc);/*左儿子左端点被覆盖,则自己左端点一定被覆盖*/
rs(p)=rs(rc);/*右儿子右端点被覆盖,则自己右端点一定被覆盖*/
v(p)=v(lc)+v(rc);/*合并条数*/
if(rs(lc)&&ls(rc))v(p)--;/*中间是连续的一段,条数-1*/
}
}
void update(int p,int l,int r,int v){
int x=l(p),y=r(p);/*l代表左区间l,值为val[l],r代表右区间r+1,值为val[r+1]*/
if(val[y+1]<=l||r<=val[x])return;
if(l<=val[x]&&val[y+1]<=r)return c(p)+=v,pushup(p),void();/*这里也需要pushup*/
update(lc,l,r,v);
update(rc,l,r,v);
pushup(p);
}
inline void addline(int p,int x,int y,int a,int b){
val[lc-1]=x;
val[lc]=a;
line[lc-1]={x,a,y,1};
line[lc]={x,a,b,-1};
}
inline int area(int n){
n<<=1;
sort(line+1,line+1+n);
sort(val+1,val+1+n);
int m=unique(val+1,val+1+n)-val-1,re=0;
build(1,1,m-1);/*注意是到m-1,[1,m-1]即[val[1],val[m]]*/
for(int i=1;i<n;i++){/*最后一条边无需统计*/
update(1,line[i].l,line[i].r,line[i].f);
re+=t[1].len*(line[i+1].h-line[i].h);/*统计面积,根节点的长度乘上与下一条线的距离就是这一块内的矩形面积*/
}
return re;
}
inline int girth(int n){
n<<=1;
sort(line+1,line+1+n);
sort(val+1,val+1+n);
int m=unique(val+1,val+1+n)-val-1;
build(1,1,m-1);
int re=0,pre=0;
for(int i=1;i<n;i++){
update(1,line[i].l,line[i].r,line[i].f);
re+=abs(pre-le(1));/*统计横边*/
pre=le(1);
re+=2*v(1)*(line[i+1].h-line[i].h);/*统计纵边*/
}
re+=line[n].r-line[n].l;/*累加最后一条线的长度*/
return re;
}
};
posted @   半步蒟蒻  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示