码迷,mamicode.com
首页 > 其他好文 > 详细

线段树合并

时间:2020-07-08 20:06:13      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:自己   lang   代码   逆序对数   新建   ons   要求   tar   节点   

(鸽 王 归 来)

算法简介

线段树合并可以将2个权值线段树合并为一个。

实现

很简单,我们的操作如下:

  1. 2棵线段树都有的节点,把它们的值合并。
  2. 只有一颗线段树有节点,那么合并出来的线段树节点的值就是这个节点的值。
  3. 依次递归下去搞定一切。

一般来说,如果不需要用合并前的线段树信息,我们就可以卡一下空间,把一棵线段树合并到另一个上:

int merge(int x,int y,int l,int r)
{
	if(!x||!y) return x+y;
	//这里写值的合并;
	int mid=(l+r)>>1;
	ls[x]=merge(ls[x],ls[y],l,mid);
	rs[x]=merge(rs[x],rs[y],mid+1,r);
	return x;
}

需要用合并前的线段树的话,空间得开2倍。这时候写个垃圾回收可以卡空间。

应用

看几道例题吧。

  1. [Vani有约会]雨天的尾巴 /【模板】线段树合并
    板子题。就差分一下再合并。

  2. [POI2011]ROT-Tree Rotations
    首先对于一个权值线段树,它的逆序对数是很好维护的。对于某一个节点,它的子节点已经维护好了权值没有跨过\(mid\)的逆序对,那么对于跨过\(mid\)的逆序对,只需要把子节点的权值数量乘起来就行了。

那么我们现在,要用树上一个点的2个儿子更新它自己的信息,就是要求把2个儿子对应的叶子节点区间合并了。那么就用线段树合并,合并时用上述思路计算2种情况跨过\(mid\)的逆序对数量。

  1. [省选联考 2020 A 卷] 树
    好家伙,新鲜出炉的省选题。

注意:这里我们数一个数的位,都是从后往前数。

我们的思路很清晰:用01trie维护每个点。对于某一个点,我们把子树的01trie合并起来(trie合并和线段树合并一个道理,代码几乎一样),再整体加\(1\),最后插入该点的权值。现在要解决的问题是如何整体\(+1\)
我们思考对一个\(2\)进制数\(+1\)的后果,考虑当前位置已经处理完了,要处理下一位(也就是要处理trie的子节点),那么假设下一位是\(0\)\(+1\)后就变成\(1\);假设下一位是\(1\)\(+1\)后就变成\(0\)。也就是说下一位\(01\)取反了,于是直接交换左右子树。

同时如果下一位原先是\(1\),现在变成了\(0\),那我们还要考虑进位,于是递归到左子树(因为下一位已经变成\(0\)了)继续加。假如下一位现在变成\(0\),但左子树没有右儿子,那么对于左子树还要新建一个右儿子(相当于你还要添一位)。

于是这道神奇的题就解决了。

线段树合并

标签:自己   lang   代码   逆序对数   新建   ons   要求   tar   节点   

原文地址:https://www.cnblogs.com/SKTT1Faker/p/13232277.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!