2025.3.1 闲话:扫描线线段树空间问题
先看正常的线段树代码片段:
void add(int l,int r,int x,int p=1) { if(l<=tree[p].l&&tree[p].r<=r) { tree[p].dat+=x*tree[p].get_len(); tree[p].lazy+=x; return; } spread(p) int mid=tree[p].get_mid(); if(l<=mid) add(l,r,x,p<<1); if(r>mid) add(l,r,x,p<<1|1); update(p); return; }
可以看到,对于叶节点,我们不会执行 update(p)
,因为只要进入了叶节点,那么开头的判断条件一定成立,直接 return
了。
在这种情况下,线段树大小是 \(4n\)。
再来看扫描线所用线段树的代码片段:
inline void update(int p) { if(tree[p].cnt) tree[p].len=from[tree[p].r+1]-from[tree[p].l]; else tree[p].len=tree[p<<1].len+tree[p<<1|1].len; return; } void Add(int l,int r,int x,int p) { if(l<=tree[p].l&&tree[p].r<=r) tree[p].cnt+=x; else { int mid=tree[p].l+tree[p].r>>1; if(l<=mid) Add(l,r,x,p<<1); if(r>mid) Add(l,r,x,p<<1|1); } update(p); return; }
可以看到,在这种情况下即使是叶节点也会执行 update
函数,而 update
可能访问当前节点的子节点(即使叶节点的子节点为空)。
而普通线段树的叶节点最大编号为 \(4n\),这里叶节点还要访问子节点,那么这里就不得不开 \(8n\) 的空间(或者可以对叶节点特判)。
\(n\) 表示元素数量,而扫描线中线段树所存元素数量为两倍矩形数量,所以前面的 \(n\) 其实是 \(2n\)。因此扫描线线段树空间应开 \(16n\)(真吓人)。
本文采用 「CC-BY-NC 4.0」 创作共享协议,转载请注明作者及出处,禁止商业使用。
作者:Jerrycyx,原文链接:https://www.cnblogs.com/jerrycyx/p/18755599
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步