[线段树系列 #4] 线段树分裂

[线段树系列 #4] 线段树分裂

简单介绍

线段树分裂,可以简单理解为把所需的链单独取出来,即为合并的逆操作

线段树分裂只适用于有序的序列,无序的序列是没有意义的,常用在动态开点的权值线段树。

思路概述

一颗区间为 \([1,n]\) 的线段树中分裂出 \([l,r]\),并建一颗新树

从 1 号结点开始递归分裂,当节点不存在或者代表的区间与 \([l,r]\) 没有交集时直接回溯。

当与 \([l,r]\) 有交集时直接开一个新结点。

当被包含于 \([l,r]\)​ 时,需要将当前结点直接接到新的树下面,并与旧父节点断开

关于复杂度,易得被断开的边为 \(\log n\) 条,所以每次分裂都为 \(O(\log n)\)

具体实现

void split(ll x, ll &y, ll k){ // 原根为x, 移至y
	if(x == 0) return;
	y = newnode();
	ll v = t[t[x].l].val;
	if(k > v) split(t[x].r, t[y].r, k-v);
	else swap(t[x].r, t[y].r);
	if(k < v) split(t[x].l, t[y].l, k);
	t[y].val = t[x].val-k;
	t[x].val = k;
}

应用

P5494 【模板】线段树分裂

附录:一篇写的很好的博客链接

posted @ 2025-07-14 16:13  Hirasawayuiii  阅读(7)  评论(0)    收藏  举报