线段树扫描线
线段树扫描线,矩形面积并,面积的求法模拟扫描线从下向上扫过图形,并快速计算当前扫描线被截得的长度。将横边赋上不同的权值,下边为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; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探