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\)(真吓人)。

posted @ 2025-03-06 15:59  Jerrycyx  阅读(34)  评论(0)    收藏  举报