




已阅读5页,还剩54页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
线段树及其应用,江苏省华罗庚中学xxxoxxxxxp,为什么要用线段树?,例1:有M个数排成一列,初始值全为0,然后做N次操作,每次我们可以进行如下操作:(1)将指定区间的每个数加上一个值;(2)将指定区间的所有数置成一个值;(3)询问一个区间上的最小值、最大值、所有数的和。,为什么要用线段树?,一般的模拟算法:用一张线性表表示整个数列,每次执行前两个操作的时候,将对应区间里的数值逐一进行修改,执行第三个操作的时候,线性扫描询问区间,求出三个统计值,每次维护的时间复杂度O(m),整体的时间复杂度O(mn)。,为什么要用线段树?,readln(m,n);fori:=1tondobeginread(t);ift=1/指定区间加上一个值thenbeginreadln(left,right,x);forj:=lefttorightdoaj:=aj+x;end;,ift=2/指定区间置成一个值thenbeginreadln(left,right,x);forj:=lefttorightdoaj:=x;end;,为什么要用线段树?,ift=3/询问一个区间的最小值、最大值、和thenbeginreadln(left,right);min:=aleft;max:=aleft;sum:=aleft;forj:=left+1torightdobeginifajmaxthenmax:=aj;sum:=sum+aj;end;writeln(min,max,sum);end;,为什么要用线段树?,机器配置:Pentium1.3G512M,时间复杂度是线性的!,为什么要用线段树?,当m、n的值比较大时,这个算法就太低效了。其低效的原因主要是我们在每一次操作中都是针对每个元素进行维护的,而这里我们进行的操作都是针对一个区间进行操作的。假如设计一种数据结构,能够直接维护所需处理的区间,那么就能更加有效地解决这个问题。,线段树(区间树),线段树的结构,定义1:长度为1的线段称为元线段。定义2:一棵树被称为线段树,当且仅当这棵树满足如下条件:(1)该树是一棵二叉树;(2)树中的每一个结点都对应一条线段a,b;(3)树中的结点是叶子结点,当且仅当它所代表的线段是元线段;(4)树中非叶子结点都有左右两棵子树,左子树树根对应线段a,(a+b)/2,右子树树根对应线段(a+b)/2,b。,线段树的结构,如T(1,10)的结构:,线段树的结构,常用的是需要对数列进行处理,将区间a,b分解为a,(a+b)/2,(a+b)/2+1,b,当a=b时表示为一个叶子结点,表示数列中的一个数。,线段树的性质,性质1:长度范围为1,L的一棵线段树的深度不超过log2(L-1)+1;性质2:线段树上的结点个数不超过2L个;性质3:线段树把区间上的任意一条线段都分成不超过2log2L条线段。,线段树的存储方式,(1)链表实现:Node=TNode;TNode=recordLeft,Right:integer;LeftChild,RightChild:Node;end;(2)数组模拟链表:Left,Right,LeftChild,RightChild:array1.nofinteger;(3)堆的结构:根节点为1,对于结点x,其左孩子为2x,右孩子为2x+1,线段树的基本操作及实现,线段树的构造procedurebuild(cur:Node;l,r:integer);begincur.Left:=l;cur.Right:=r;ifl=rthenbegincur.LeftChild:=nil;cur.RightChild:=nil;endelsebeginnew(cur.LeftChild);new(cur.RightChild);build(cur.LeftChild,l,(l+r)div2);build(cur.RightChild,(l+r)div2+1,r);end;end;,线段树的基本操作及实现,线段树的查询procedurequery(cur:Node;l,r:integer);varLC,RC:Node;beginLC:=cur.LeftChild;RC:=cur.RightChild;if(l(cur.Left+cur.Right)div2thenquery(RC,l,r);end;end;,线段树的维护方法,对区间进行修改,对元素进行修改,设置为同一个数,统一加上一个数,修改,查询,区间的和,区间的最大值,区间的最小值,其它,线段树的维护方法,如果想要让线段树发挥实际的作用,必须在每个结点上维护额外的域来记录更多的信息。首先看一个引例的弱化版,假设每次修改操作只能对其中某个元素进行修改。在每个结点上额外维护3个域:max、min、sum,分别表示子树上的最大值、最小值和所有元素的和。,(1)对元素进行修改,procedureinsert(cur:Node;x,num:integer);varLC,RC:Node;beginLC:=cur.LeftChild;RC:=cur.RightChild;ifcur.Left=cur.Right/对叶结点的处理thenbegincur.Min:=num;cur.Max:=num;cur.Sum:=num;endelsebeginifx(cur.Left+cur.Right)div2theninsert(RC,x,num);cur.Sum:=LC.Sum+RC.Sum;/上推if(LC.MaxRC.Max)thencur.Max:=LC.Maxelsecur.Max:=RC.Max;if(LC.MinRC.Min)thencur.Min:=LC.Minelsecur.Min:=RC.Min;end;end;,(2)对区间进行查询,functionquerysum(cur:Node;l,r:integer):integer;varLC,RC:Node;ret:integer;beginLC:=cur.LeftChild;RC:=cur.RightChild;ret:=0;if(l(cur.Left+cur.Right)div2thenret:=ret+querysum(RC,l,r);end;querysum:=ret;end;,(3)对区间修改(统一加上一个数),procedureupdate(cur:Node;l,r,delta:integer);varLC,RC:Node;/需要给每个区间增加一个变量deltabeginLC:=cur.LeftChild;RC:=cur.RightChild;if(l(cur.Left+cur.Right)div2thenupdate(RC,l,r,delta);cur.Sum:=LC.Sum+LC.Delta*(LC.Right-LC.Left+1);cur.Sum:=cur.Sum+RC.Sum+/上推RC.Delta*(RC.Right-RC.Left+1);end;end;,(4)对区间查询,functionquerysum(cur:Node;l,r:integer):integer;varLC,RC:Node;ret:integer;beginLC:=cur.LeftChild;RC:=cur.RightChild;ret:=0;if(l(cur.Left+cur.Right)div2thenret:=ret+querysum(RC,l,r);end;querysum:=ret;end;,(5)对区间修改(设置为同一个数),procedureupdate(cur:Node;l,r,num:integer);varLC,RC:Node;beginLC:=cur.LeftChild;RC:=cur.RightChild;ifcur.En/如果该区间已经是同一个值,将值下传给左右区间thenbegincur.sum:=(cur.right-cur.left+1)*cur.data;ifLCnilthenbeginLC.Data:=cur.Data;LC.En:=true;end;ifRCnilthenbeginRC.Data:=cur.Data;RC.En:=true;end;cur.En:=false;end;if(l(cur.Left+cur.Right)div2thenupdate(RC,l,r,num);cur.Sum:=calcsum(LC)+calcsum(RC);end;end;,functioncalcsum(cur:Node):integer;beginifcur.Enthencalcsum:=(cur.Right-cur.Left+1)*cur.Dataelsecalcsum:=cur.Sum;end;,(6)对区间查询,functionquerysum(cur:Node;l,r:integer):integer;varLC,RC:Node;ret:integer;beginLC:=cur.LeftChild;RC:=cur.RightChild;ret:=0;if(l(cur.Left+cur.Right)div2thenret:=ret+querysum(RC,l,r);end;querysum:=ret;end;,线段树的维护方法,线段树上的参数通常有两种维护方法:(1)一类参数表达了结点的性质,通常具有树型的递推性质,可以从下向上进行递推计算;(如sum,max,min)(2)一类参数表达了子树的性质,维护的时候可以先打上标记,在需要进一步访问其子结点的时候从上向下传递。(如delta,en),线段树的维护方法,线段树上维护或者询问过程的一般过程:对于当前区间l,rif达到某种边界条件(如叶结点或被整个区间完全包含)then对维护或是询问作相应处理else将第二类标记传递下去(注意,在查询过程中也要处理)根据区间的关系,对两个孩子结点递归处理利用递推关系,根据孩子结点的情况维护第一类信息,为什么要用线段树?,应用举例,例2、线段覆盖在所有不大于30000的自然数范围内讨论一个问题:已知n条线段,把端点依次输入告诉你,然后有m(30000)个询问,每个询问输入一个点,要求这个点在多少条线段上出现过。,n=4m=3线段:0,34,62,65,7询问:1,3,5,应用举例(线段覆盖),可以直接对问题处理的区间建立线段树,在线段树上维护区间被覆盖的次数。将n条线段插入线段树,然后对于询问的每个点,直接查询被覆盖的次数即可。,应用举例(线段覆盖),这道题目完全可以不用线段树,将每个线段拆分成(L,+1),(R+1,-1)的两个事件点,每个询问点也在对应坐标处加上一个询问的事件点,排序之后扫描就可以完成题目的询问。,Sum112223310,+1,-1,-1,-1,+1,+1,+1,-1,应用举例(线段覆盖),因为此问题是一个离线的问题,这是一个很简单的离线算法。线段树在处理在线问题的时候会更加有效,因为它维护了一个实时的信息。,应用举例,例3、售票系统某次列车途经C个城市,城市编号依次为1到C,列车上共有S个座位,每一个售票申请包含三个参数,分别用O、D、N表示,O为起始站,D为目的地站,N为车票张数,售票系统对该售票申请作出受理或不受理的决定。只有在从O到D的区段内列车上都有N个或N个以上的空座位时该售票申请才被受理。1=C=60000,1=S=60000,1remainthenret:=falseelseret:=trueelseif(remain-cur.delta=0)thenbeginifl(cur.left+cur.right)div2thenret:=retandtest(rc,l,r,x,remain-cur.delta)end;test:=ret;end;,应用举例,例4、采矿金矿的老师傅年底要退休了。经理为了奖赏他的尽职尽责的工作,决定送他一块长方形地。长度为S,宽度为W。老师傅可以自己选择这块地。显然其中包含的采金点越多越好。你的任务就是计算最多能得到多少个采金点。如果一个采金点的位置在长方形的边上,它也应当被计算在内。读入采金点的位置。计算最大的价值。数据范围:1=s,w=100001=s,w=10000-300000thencur.sum:=cur.sum+rc.right-rc.leftelsecur.sum:=cur.sum+rc.sum;end;end;,应用举例(面积),主程序:fori:=1to30000dobeginaddi:=nil;deli:=nil;end;readln(n);fori:=1tondobeginreadln(x1,y1,x2,y2);new(p);p.h1:=y1;p.h2:=y2;p.next:=addx1;addx1:=p;new(p);p.h1:=y1;p.h2:=y2;p.next:=delx2;delx2:=p;end;,new(tree);build(tree,0,30000);sum:=0;fori:=0to30000dobeginp:=deli;whilepnildobeginupdate(tree,p.h1,p.h2,0);p:=p.next;end;p:=addi;whilepnildobeginupdate(tree,p.h1,p.h2,1);p:=p.next;end;iftree.delta0thensum:=sum+30000elsesum:=sum+tree.sum;end;writeln(sum);,应用举例,例6、蛇在平面上有N个点,现在要用一些线段将它们连起来,使其满足以下要求:(1)这些线段必须闭合(2)线段的端点只能是这N个点(3)交于一点的两条线段成90度角(4)线段都必须平行于X轴或Y轴(5)所有线段除了在这N个点外不相交(6)所有线段的长度之和必须最短如果存在这样的线段,则输出最小长度,否则输出0。,应用举例(蛇),1、所有线段都要和坐标轴平行,所以每个点只能与上下左右四个点相连,由于与一个点相连的两条线段成90度,每个顶点必须与一条平行于X轴和一条平行于Y轴的线段相连。2、在同一水平线上的点中,按X轴排序后设为P1,P2,Pn,P1必须与P2相连,P3必须与P4相连,在同一垂直线上的点也同样,所以线段的构造是唯一的。,应用举例(蛇),3、由于解是唯一的,是否相连只要广度扩展就可判断了,关键在于判断由上述方法所构造出的线段是否合法(满足线段不在N个点之外自交)。,不相连不合法,不自交合法,自交不合法,应用举例(蛇),4、由于所有线段与坐标轴平行,有明显的区间性,可以用线段树判断是否自交:(1)先将所有的线段按X坐标排序,注意线段在端点重合不算自交,所以X轴坐标相同时,事件的顺序要恰当处理:右端点优先,其次是与Y轴平行的线段,最后是左端点。,应用举例(蛇),(2)将Y轴表示的区间建立线段树,每个线段或线段的端点作为一个事件。按X坐标由小到大,扫描所有事件:平行于X轴线段的左端点,就把Y坐标插入到线段树中;平行于X轴线段的右端点,就把Y坐标从线段树中删除;平行于Y轴的线段,假设该线段的Y坐标分别为y1和y2,就在线段树中查询y1,y2区间内是否有点存在,如果存在就说明有线段和它
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 系统化运营:夫妻二人共同投资茶馆的合伙协议
- 《涉及房产、股权、债务的夫妻离婚财产分割协议》
- 数字化云平台租赁电信机房服务器及维护服务合同
- 离异家庭子女抚养权、探望权及财产分割执行合同
- 智能家居平台合作合同续签及用户体验优化协议
- 2025年医疗器械国产化趋势下国际市场拓展与品牌建设研究报告
- 2025年制造业数据治理与工业互联网安全防护体系建设策略分析报告
- 汽车行业智能网联汽车2025年信息安全与隐私保护研究报告
- 中职专业笔试题库及答案
- 动物脱逃应急预案(3篇)
- 急性ST段抬高型心肌梗死的护理课件
- DBJ50-T-200-2024 建筑桩基础技术标准
- 企业法制讲座课件
- 内分泌健康宣教
- 【高朋律师事务所】RWA发展研究报告:法律、监管和前瞻(2025年)
- 汽车网销电话邀约话术培训
- 2025至2030中国电动汽车用电动机行业项目调研及市场前景预测评估报告
- 2025年福州房地产市场分析报告
- 诗词格律培训课件
- 《大学生心理健康教育》课程教案
- 音乐感知:从听觉到绘画
评论
0/150
提交评论