线段树及其应用.docVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
线段树及其应用李子星 【摘要】 这篇文章写的是关于线段树这种数据结构的理论和我总结的一些应用方法。理论部分主要分析了线段树的空间复杂度和一些操作的时间复杂度。应用部分则是结合9个例题来分析,例题都是一些数学模型,而不是具体的问题,更具扩展性。程序代码也是对算法的一种说明,因此也是本文中的重要的一部分,代码中有详细的注释。但完整的代码则没有什么价值,因此文中有的代码都是片断。 因为都是按自己的想法写的,所以可能很多地方描述不清,证明也不严密。虽然很多知识也是来自他人,但一是因为时间太久,二是因为来源太杂,我实在想不起哪出自哪了,所以也没有添加引用。 【关键词】 线段树、数据结构、二叉树、覆盖、坐标离散化 【正文】 一、定义 线段树又可以称为区间树,是一颗二叉树,记为T(a,b),参数a,b表示该树表示区间[a,b],区间的长度就是b-a。递归定义T(a,b): 若b-a1:T(a,(a+b)/2)为T的左子树,T((a+b)/2,b)为T的右子树。(除法为整除,下同) 若b-a=1:T为一个单节点树。 易知,线段树的每个节点要么没有子节点,要么就有2子节点。 二、关于线段树的理论 区间总长为L的线段树,至多有[log2L]+1层和2*L个节点。每一条线段都可以被不多于2*[log2 对于[a,b]的任意一个子区间[c,d],将[c,d]的补集放在T(a,b)的上方,假设现在是正午12点,阳光从正上方照射下来(见下图)。将不能被完全照射到的区间的节点拿掉,再把被遮着的区间的节点拿掉,将剩下的节点构成的集合记为S。S集有以下3个特性: 集合S中的任2个节点的区间都没有交集,因为若A与B有交集,则A、B中必定是一上一下,层次较深的节点的区间必定存在阴影部分(相交的那一部分),而有阴影的区间所代表的节点是不能存在于S中的; 对于集合S中的任意一个节点,最多只存在一个与其同层的另一节点也在S集中。也就是说,在T的每一层,至多只有2个节点在S中。(!!!证明)所以,S的大小将不大于2*(T的最大深度)=2*[log2L 集合中的所有区间的并就是[c,d]。 为方便后面的叙述,将按上面的方法构造的S集中的节点称为[c,d]的组成节点。 而通过递归从根节点开始遍历这些节点的时间复杂度也是O(log2L)(只访问所有的组成节点和其前辈节点,合起来将不多于4*[log2 // 定义线段树类型 linetree typedef struct{ int f, t; linetree *le, *ri; } linetree; // 创建线段树 linetree *maketree(int from, int to){ linetree *p=malloc(sizeof(linetree)); p-f=from; p-t=to; if (to-from1){ p-le=maketree(from,(from+to)/2); p-ri=maketree((from+to)/2,to); } else p-le=p-ri=NULL; return p; } // 遍历区间 [from,t] 的所有组成节点 void search(linetree *p, int from, int to){ // [from,t]与p没有交叉区域 if (p==NULL||to=p-f||from=p-t) return; // [from,t]与p交叉区域是p的全部 if (from=p-f(to=p-t){ // p是组成节点之一 return; }; // [from,t]与p交叉区域是p的一部分,此时p必定存在2子节点 search(p-le, from, t); search(p-ri, from, t); } 每个节点的f和t参数其实也是可以省略的,因为这个值实际上是个常量,树建立好后就不会变的,因此只要在调用search的时候多带入2个参数,每个节点就可以省掉这2个int的空间,整颗树就省掉了16*L Byte的空间。 void new_search(linetree *p, int from, int to, int pf, int pt){ // [from,t]与p没有交叉区域 if (p==NULL||to=pf||from=pt) return; // [from,t]与p交叉区域是p的全部 if (from=pf(to=pt){ // p是组成节点之一 return; }; // [from,t]与p交叉区域是p的一部分,此时p必定存在2子节点 search(p-le, from, to, pf, (pf+pt)/2); search(p-ri, from, to, (pf+pt)/2, pt); } 如果区间总长L

文档评论(0)

小教资源库 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档