- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
线段树的合并
线段树的合并——不为人知的实用技巧
杭州二中 黄嘉泰
线段树?
OI中最常用的数据结构
形式化的线段树:
有一列元素
上有二元运算 ,使得对于任意 ,都有 ,并且 满足结合律。( 是半群)
另外, 运算必须能高效地计算完成,譬如O(1)。
要求高效地支持:
修改某个 ;
给定 ,回答 。
线段树
由于+运算有结合律,设法维护一些连续元素的和,使得每个元素出现在O(logn)个维护的和当中,每个询问能表示成O(logn)个维护的和的和。
一个简单有效的办法就是现在常用的“线段树”。从[1,n]开始,把每段连续的元素尽可能均匀地分成两半,直到成为单个元素为止。
这个关系构成了一棵近似丰满的二叉树,每个节点代表了一些连续(或单个)元素,我们在上面维护它们的和。
线段树
具体实现不再赘述
一些常见的问题譬如维护区间和由于其特殊性,可以在支持对连续的一段元素做出某种程度的修改的前提下,仍然高效地维护区间和。一般情况下不一定能这么做。
有时也用来实现map,这时key是字长内的整数,同时能维护key连续的一些元素的信息。
线段树的特点
当确定了元素个数n,或者key的范围[1,U],建出的线段树形态是唯一的。
对两棵key的上界相同的线段树进行参数相同的单点更新/区间询问时,所访问到的节点也是一致的。
由此我们有了一些喜闻乐见的线段树用法。(详见CLJ去年hw2)
今天的内容也依赖于线段树严格的结构
线段树的合并
根据线段树的定义我们不难写出下面的过程,来合并两棵代表范围相同的线段树
由于a,b两棵树结构相同,上面的过程的正确性是显然的。
a,b中可能存在key相同的元素,我们之前对线段树的定义对这种情况无能为力,所以需要一个merge_leaf过程来给出新树中该位置的元素
为了方便确定一棵树是否为空,动态开辟节点。若某棵子树为空,则其父亲的对应指针为空。
merge(a,b):
如果a,b中有一个不含任何元素,就返回另一个
如果a,b都是叶子,返回merge_leaf(a,b)
返回merge(a-l,b-l)与merge(a-r,b-r)连接成的树
例子
维护区间内数字个数
复杂度?
若merge_leaf过程和+运算的代价都是O(1),容易看出合并的开销正比于两棵树公共的节点数
单次merge操作的开销可大可小,但我们可以立即得到一个非常有用的结论:
若有n棵含有单个元素的树,经过n-1次merge操作,将他们合并成一棵的代价是O(nlogn)或O(nlogU)
理由:这个过程的开销不会比向一棵空树顺序插入n个整数来的大。
另一种风格的线段树
以合并操作为核心,我们可以写出另一种风格的线段树
关键操作:
merge_leaf过程
连接操作
merge过程
make_leaf过程
操作都自顶向下,可以方便地持久化
线段树合并VS启发式合并
OI中常常遇到一些题目,要将若干物件不断合并,顺便计算一些信息。
有些以树为背景的题目也需要完成类似的工作。
其中很大一部分需要维护一些元素的有序序列,通常用平衡树的启发式合并解决。复杂度O(nlog^2n)
关键字通常是不太大的整数,如果换用这里的线段树合并,就可以降低复杂度的阶,做到O(nlogn)或O(nlogU)。
下面看几个例子
POI18 rot
给一棵2n-1个节点的二叉树,每个叶子上有一个1-n的数字,保证每个数字出现且仅出现一次。
现在允许任意次交换某两棵兄弟子树
对操作完毕的树进行dfs,可以得到一个先序遍历序,它是一个1-n的排列
求这个排列最小的逆序对数
POI18 rot
若T不是叶子,T的逆序对数=T-l的逆序对数+T-r的逆序对数+(xy|xϵT-l,y ϵT-r)的对数
前两个与是否交换T-l和T-r无关,并且互相独立
计算每棵子树经过调整后最小的逆序对数。若子树已经计算完毕,只需知道交换两棵子树与不交换两种情况下新增的逆序对数,选取小的方案。
用平衡树维护子树内数字的有序序列,启发式合并时顺便算出需要的信息。
O(nlog^2n)
POI18 rot
合并一些统计区间内数字个数的线段树来解决
在执行merge的过程中统计交换与不交换产生的逆序对数
a是T-l对应线段树的某棵子树,b来自T-r的线段树
ans0表示不交换时的新增逆序对数,ans1表示交换时的新增逆序对数
时间复杂度O(nlogn)
merge(a,b):
如果a,b中有一个为空,就返回另一个
ans0+=cnt(a-r)*cnt(b-l)
ans1+=cnt(a-l)*cnt(b-r)
返回merge(a-l,b-
文档评论(0)