- 1、本文档共51页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
如何解决好动态统计问题 广东省中山市第一中学 余江伟 wintokk@ 【引言】 在信息学竞赛中,统计问题十分常见。请看一个例子: 在长度为N (2≤N≤106)的序列上进行M次以下操作: 【引言】 利用线段树,可以轻松设计出时间复杂度O(MlogN)、空间复杂度O(N) 的算法。 详见2004年薛矛前辈的论文 【引言】 线段树在本题取得成功的原因 高效的组织结构 很好地支持区间操作 前提条件——本题中,序列项与项之间隐含着严格不变的次序关系 当统计对象次序发生大规模变化,线段树就显得力不从心了,必须寻找更优秀的解法 【例一】维护序列 (NOI2005) 写一个程序维护一个序列,支持6种操作: INSERT a {cn} 在序列第 a 项后插入长度为 n 序列 DELETE a b 删除序列的第 a 项到第 b 项 MAKE-SAME a b c 把序列的第 a 项到第 b 项的值统一改为c REVERSE a b 把序列的第 a 项到第 b 项首尾翻转后放回原位 GET-SUM a b 输出序列的第 a 项到第 b 项的和 MAX-SUM 求序列中和最大的一段非空子列,并输出最大和 【例一】维护序列 (NOI2005) 写一个程序维护一个序列 INSERT a {ck} DELETE a b MAKE-SAME a b c REVERSE a b GET-SUM a b MAX-SUM 【例一】维护序列 (NOI2005) 初步分析 本题需要模拟一个序列的变化过程并随时统计相关求和信息 具有操作种类多、规模大的特点 朴素算法 数组/链表模拟,只能拿到部分分数 更优秀的算法 块状链表(参考解答),综合数组、链表的优势 树形结构 【例一】维护序列 (NOI2005) 关键问题——表示操作 【例一】维护序列 (NOI2005) 关键问题——表示操作 如何表示 二叉查找树(BST)表示序列 每个节点记录一个数 BST中序遍历结果为原序列 一棵表示(-5,-2,-1,1,6,-7,8,10,-5,19,0,21,22,3,-4)的BST 【例一】维护序列 (NOI2005) 关键问题——表示操作 如何操作 不难发现,大多数操作都是围绕某个“连续段”进行的 “连续段”在BST中可能比较分散,我们希望把这些节点聚集起来 伸展树 【例一】伸展树简介 伸展树是一种自适应(Self-Adjusting)的BST。具体地说,每次访问一个节点后,按照一定规则进行旋转,将其调整为树的根。 【例一】伸展树简介 伸展树是一种自适应(Self-Adjusting)的BST。具体地说,每次访问一个节点后,按照一定规则进行旋转,将其调整为树的根。 伸展树的旋转规则 Zig/Zag Zig-Zig/Zag-Zag Zig-Zag/Zag-Zig 【例一】伸展树简介 伸展树是一种自适应(Self-Adjusting)的BST。具体地说,每次访问一个节点后,按照一定规则进行旋转,将其调整为树的根。 伸展树的旋转规则 Zig/Zag Zig-Zig/Zag-Zag Zig-Zag/Zag-Zig 【例一】伸展树简介 伸展树是一种自适应(Self-Adjusting)的BST。具体地说,每次访问一个节点后,按照一定规则进行旋转,将其调整为树的根。 伸展树的旋转规则 Zig/Zag Zig-Zig/Zag-Zag Zig-Zag/Zag-Zig 【例一】伸展树简介 伸展树是一种自适应(Self-Adjusting)的BST。具体地说,每次访问一个节点后,按照一定规则进行旋转,将其调整为树的根。 伸展树的旋转规则 Zig/Zag Zig-Zig/Zag-Zag Zig-Zag/Zag-Zig 【例一】伸展树简介 按照以上规则将节点调整到根的过程称为伸展操作。可以证明,伸展操作的平摊复杂度为O(logN)。 利用伸展操作,可以完成所有BST的基本操作。 针对本题,在节点上记录子树的大小(Size),可以实现第K个节点的查找功能(SplayKth)。这也是解决本题的核心过程。 【例一】核心过程伪代码(1) SplayKth(p, kth) // 把以 p为根的子树下第kth个节点提到子树的根,并返回节点编号 if Size[Left[p]]+1 = kth then return p if Size[Left[p]] ≥ kth then x ← Left[p] if Size[Left[x]]+1 = kth then return Zig( x, p ) if Size[Left[x]] ≥ kth then
文档评论(0)