线段树合并学习笔记

模板:P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并

好像一直没写过 来补一下

首先线段树合并只针对动态开点线段树而言(要都是完整线段树还合个锤子

有两种写法

第一种是直接把 \(y\) 合到 \(x\) 之后就干掉 需要离线下来合并完立即统计答案

void merge(int x, int y, int l, int r) {
	if (!x || !y) return x + y;
	if (l == r) {
		tr[x] += tr[y];
		return x;
	}
	ls[x] = merge(ls[x], ls[y], l. mid);
	rs[x] = merge(rs[x], rs[y], mid + 1, r);
	pushup(x);
	return x;
}

第二种是像主席树那种新建节点 支持在线 缺点是空间复杂度 \(\text{O}(n \log n)\)

void merge(int x, int y, int l, int r) {
	if (!x || !y) return x + y;
	int k = ++tot;
	if (l == r) {
		tr[k] = tr[x] + tr[y];
		return k;
	}
	ls[k] = merge(ls[x], ls[y], l, mid);
	rs[k] = merge(rs[x], rs[y], mid + 1, r);
	pushup(k);
	return k;
}

复杂度分析:不难发现 在函数最开始不被直接遣返的充要条件是两棵树共同都有这个节点
所以感性理解就是两树节点的交集级别的
那么对于那棵比较小的树而言 每次合并至少增大一倍
因为最后并完是一棵完整的线段树 所以复杂度就是 \(\text{O}(n \log n)\)

感觉写的好水 但是想不到能写啥了 就先这样吧

posted @ 2023-11-06 15:07  Steven24  阅读(8)  评论(0编辑  收藏  举报