简单线段树合并

理解

顾名思义,就是把两棵线段树的信息合并起来。

暴力合并很好想,把两棵树一起遍历一遍就是了,复杂度O(n)

但是很多情况下我们需要多次合并两棵并不饱满的线段树(此处“不饱满”意思是有些区间根本没有用过),空间和时间都过不去,

所以就用到一些优化。

思路

怎么优化空间呢?很简单,动态开点。

(这里不开链接了,直接安利一下动态开点,懂的跳过:

其实就是把每个节点的左右儿子记录(不再用id*2,id*2+1直接访问),初始为零,当需要往下插入时才赋值为两个新的点(简称开点),查询就不用开点了,特判一下就行

完了)

使用了动态开点后,你再用暴力遍历的方式合并:

inline int mergg(int x,int y,int l,int r){
	if(!x||!y)return x|y; //两节点其中一个为零,另一个补上去
	int mid=(l+r)>>1;
	t[x].ls=mergg(t[x].ls,t[y].ls,l,mid),t[y].ls=0; //合并左子树
	t[x].rs=mergg(t[x].rs,t[y].rs,mid+1,r),t[y].rs=0; //合并右子树
	.../*此处合并两点信息*/
	return x;
}

虽然看上去还是O(n),但是(大多数问题中)当每次合并的树的大小总和有限制的时候,总复杂度是O(nlogn),比非动态的O(n^2)快得多。

例题:ZZH的旅行

猜你喜欢

转载自blog.csdn.net/weixin_43960287/article/details/110474047