线段树合并
将两颗权值线段树合并的操作,被称为线段树合并。
合并时对应位置上的权值相加,如下图所示。
将两颗满二叉树合并,复杂度必然是 O(nlogn) 。
如果现有 n 颗动态开点权值线段树,这些线段树上最多有 m 种不同的权值。
代码实现如下:
int merge(int x, int y, int l, int r) {
if (!x || !y) return x + y;
if (l == r) return x;
int mid = l + r >> 1;
tr[x].l = merge(tr[x].l, tr[y].l, l, mid);
tr[x].r = merge(tr[x].r, tr[y].r, mid + 1, r);
return x;
}
每合并两颗线段树,时间复杂度为两线段树上的重叠部分。
合并所有线段树,复杂度就是 O(mlogn) 。
例题 : 雨天的尾巴
线段树分裂
将一颗权值线段树分裂成两颗的操作,被称为线段树分裂。
一般指原有线段树的下表为 [1,n] ,然后将 [s,t] 的一段取出,得到两颗线段树。
先看代码:
void split(int &p, int &q, int s, int t, int l, int r) {
if (t < l || r < s) return;
if (!p) return;
if (l <= s && t <= r) {
q = p; p = 0;
return;
}
if (!q) q = ++ tot;
int mid = s + t >> 1;
if (l <= mid) split(tr[p].l, tr[q].l, s, mid, l, r);
if (r > mid) split(tr[p].r, tr[q].r, mid + 1, t, l, r);
pushup(p), pushup(q);
}
类似线段树合并,时间复杂度仍然是两线段树上的重叠部分,总时间复杂度 O(mlogn) 。
例题 : 线段树分裂