说到线段树,想来大家并不陌生——最基本的思路就是将其规划成块,然后只要每次修改时维护一下即可。

但是尤其是涉及到区间修改时,lazytag的使用往往能够对于程序的质量起到决定性作用(Ex:一般JSOI2008左右的线段树题目,如果有区间修改的话,那么假如普普通通的一个个修改的话,那么一般30分左右,甚至更少;而有了神奇的lazytag,只要别的地方写的还算基本到位,一般就Accept了)

lazytag的基本思想也就是在需要修改的区间打上标记,然后下次动态维护标记和真正值之间的关系,然后查询或者下一个修改操作涉及此区间时,进行进一步维护。

于是,此时就存在两种不同的查询操作了(此处以BZOJ1798为例)

方案一:当查询过程中,遇到了带有标记的点,则将其记录下来(即并入综合的修改参数里面),然后当刚好找到合适区间是,再操作之

  1. function cal(z,x,y,l,r:longint;d:vet):int64;inline;
  2. var d1:vet;
  3. begin
  4. if l>r then exit();
  5. d1:=merge(b[z],d);
  6. if (x=l) and (y=r) then exit(((a[z]*d1.a0) mod p+(d1.a1*((r-l+) mod p)) mod p) mod p);
  7. exit((cal(z*,x,(x+y) div ,l,min((x+y) div ,r),d1)+cal(z*+,(x+y) div +,y,max((x+y) div +,l),r,d1)) mod p);
  8. end;

这个方案在操作时,实际上并没有动任何的标记,直接通过现有的标记求出了值

方案二:查询过程中遇到标记点的话,则将其扩展下去,保证一路下来都不存在标记点,然后到地方了之后直接返回数值

  1. function cal(z,x,y,l,r:longint):int64;inline;
  2. begin
  3. if l>r then exit();
  4. ext(z,x,y);
  5. if (x=l) and (y=r) then exit(a[z]);
  6. exit((cal(z*,x,(x+y) div ,l,min((x+y) div ,r))+cal(z*+,(x+y) div +,y,max((x+y) div +,l),r)) mod p);
  7. end;

附:ext操作和merge操作

  1. function merge(d1,d2:vet):vet;inline;
  2. var d3:vet;
  3. begin
  4. d3:=d1;
  5. d3.a0:=d3.a0 mod p;d3.a1:=d3.a1 mod p;
  6. d2.a0:=d2.a0 mod p;d2.a1:=d2.a1 mod p;
  7. d3.a0:=(d3.a0*d2.a0) mod p;
  8. d3.a1:=((d3.a1*d2.a0) mod p+d2.a1) mod p;
  9. exit(d3);
  10. end;
  11. procedure ext(z,x,y:longint);inline;
  12. begin
  13. a[z]:=((a[z]*b[z].a0) mod p+(b[z].a1*((y-x+) mod p)) mod p) mod p;
  14. b[z*]:=merge(b[z*],b[z]);
  15. b[z*+]:=merge(b[z*+],b[z]);
  16. b[z].a0:=;b[z].a1:=;
  17. end;

此方法比较直观,比较好想,但是看样子好多标记其实被操作了

好了,现在看下时间对比:(注:此两个程序中除了cal函数不一样其他均一样)

方案一:

方案二:(这个里面方案一的cal函数是通过{}注释掉的,所以代码会多出来那么些)

空间上差不多(phile:这不显然的么呵呵呵),时间上方案一要快,原因其实还是因为方案一并没有涉及到修改标记的操作,而方案二涉及了,而且尤其对于tag很密集的树,操作更是会较为复杂。还有方案二虽然更加直观易想,但是代码其实并没有缩减,两者代码复杂度几乎一样。所以综合而言,方案一更加划算么么哒

下面附上BZOJ1798代码

  1. /**************************************************************
  2. Problem:
  3. User: HansBug
  4. Language: Pascal
  5. Result: Accepted
  6. Time: ms
  7. Memory: kb
  8. ****************************************************************/
  9.  
  10. type
  11. vet=record
  12. a0,a1:int64;
  13. end;
  14. var
  15. i,j,k,l,m,n,a2,a3,a4:longint;
  16. p:int64;
  17. a,c:array[..] of int64;
  18. b:array[..] of vet;
  19. d,d1:vet;
  20. procedure built(z,x,y:longint);inline;
  21. begin
  22. if x=y then
  23. a[z]:=c[x] mod p
  24. else
  25. begin
  26. built(z*,x,(x+y) div );
  27. built(z*+,(x+y) div +,y);
  28. a[z]:=(a[z*]+a[z*+]) mod p;
  29. end;
  30. b[z].a0:=;b[z].a1:=;
  31. end;
  32. function max(x,y:longint):longint;inline;
  33. begin
  34. if x>y then max:=x else max:=y;
  35. end;
  36. function min(x,y:longint):longint;inline;
  37. begin
  38. if x<y then min:=x else min:=y;
  39. end;
  40. function merge(d1,d2:vet):vet;inline;
  41. var d3:vet;
  42. begin
  43. d3:=d1;
  44. d3.a0:=d3.a0 mod p;d3.a1:=d3.a1 mod p;
  45. d2.a0:=d2.a0 mod p;d2.a1:=d2.a1 mod p;
  46. d3.a0:=(d3.a0*d2.a0) mod p;
  47. d3.a1:=((d3.a1*d2.a0) mod p+d2.a1) mod p;
  48. exit(d3);
  49. end;
  50. procedure ext(z,x,y:longint);inline;
  51. begin
  52. a[z]:=((a[z]*b[z].a0) mod p+(b[z].a1*((y-x+) mod p)) mod p) mod p;
  53. b[z*]:=merge(b[z*],b[z]);
  54. b[z*+]:=merge(b[z*+],b[z]);
  55. b[z].a0:=;b[z].a1:=;
  56. end;
  57. function op(z,x,y,l,r:longint;d:vet):int64;inline;
  58. var
  59. a3,a4:int64;
  60. begin
  61. if l>r then exit();
  62. ext(z,x,y);
  63. if (x=l) and (y=r) then
  64. begin
  65. b[z]:=d;
  66. exit(((a[z]*((b[z].a0-) mod p)) mod p+(b[z].a1*((r-l+) mod p)) mod p) mod p);
  67. end
  68. else
  69. begin
  70. a3:=op(z*,x,(x+y) div ,l,min(r,(x+y) div ),d);
  71. a4:=op(z*+,(x+y) div +,y,max(l,(x+y) div +),r,d);
  72. a[z]:=(a[z]+(a3+a4) mod p) mod p;
  73. exit((a3+a4) mod p);
  74. end;
  75. end;
  76. {function cal(z,x,y,l,r:longint;d:vet):int64;inline; //方案一
  77. var d1:vet;
  78. begin
  79. if l>r then exit(0);
  80. d1:=merge(b[z],d);
  81. if (x=l) and (y=r) then exit(((a[z]*d1.a0) mod p+(d1.a1*((r-l+1) mod p)) mod p) mod p);
  82. exit((cal(z*2,x,(x+y) div 2,l,min((x+y) div 2,r),d1)+cal(z*2+1,(x+y) div 2+1,y,max((x+y) div 2+1,l),r,d1)) mod p);
  83. end; }
  84. function cal(z,x,y,l,r:longint):int64;inline; //方案二
  85. begin
  86. if l>r then exit();
  87. ext(z,x,y);
  88. if (x=l) and (y=r) then exit(a[z]);
  89. exit((cal(z*,x,(x+y) div ,l,min((x+y) div ,r))+cal(z*+,(x+y) div +,y,max((x+y) div +,l),r)) mod p);
  90. end;
  91.  
  92. function modd(x:int64):int64;inline;
  93. begin
  94. if x>= then exit(x mod p);
  95. modd:=((abs(x) div p+)*p+x) mod p;
  96. end;
  97.  
  98. begin
  99. readln(n,p);
  100. for i:= to n do read(c[i]);
  101. readln;
  102. built(,,n);
  103. readln(m);
  104. for i:= to m do
  105. begin
  106. read(j);
  107. case j of
  108. :begin
  109. readln(a2,a3,a4);
  110. d.a0:=a4;d.a1:=;
  111. op(,,n,a2,a3,d);
  112. end;
  113. :begin
  114. readln(a2,a3,a4);
  115. d.a0:=;d.a1:=a4;
  116. op(,,n,a2,a3,d);
  117. end;
  118. :begin
  119. readln(a2,a3);
  120. writeln(modd(cal(,,n,a2,a3)));
  121. end;
  122. end;
  123. end;
  124. end.

关于使用lazytag的线段树两种查询方式的比较研究的更多相关文章

  1. ZOJ-1610 线段树+两种查询方法(弥补我线段树区间填充的短板)

    ZOJ-1610 线段树+两种查询方法(弥补我线段树区间填充的短板) 题意 题意:给一个n,代表n次操作,接下来每次操作表示把[l,r]区间的线段涂成k的颜色其中,l,r,k的范围都是0到8000 这 ...

  2. codevs 2216 线段树 两种更新方式的冲突

    题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决 ...

  3. easyui datagride 两种查询方式

    easyui datagride 两种查询方式function doReseach() { //$('#tt').datagrid('load', { // FixedCompany: $('.c_s ...

  4. HashMap两种遍历方式的深入研究

    转自:http://swiftlet.net/archives/1259 HashMap的遍历有两种方式,如下所示:第一种利用entrySet的方式:   1 2 3 4 5 6 7 Map map ...

  5. js的两种查询方式 LHS and RHS

    为了进一步理解,我们需要多介绍一点编译器的术语.编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过查找变量 a 来判断它是否已声明过.查找的过程由作用域进行协助,但是引擎执行怎样的查找,会影响 ...

  6. mysql查询字段类型为json时的两种查询方式。

    表结构如下: id        varchar(32) info     json 数据: id = info = {"age": "18","di ...

  7. POJ 3225 线段树区间更新(两种更新方式)

    http://blog.csdn.net/niuox/article/details/9664487 这道题明显是线段树,根据题意可以知道: (用0和1表示是否包含区间,-1表示该区间内既有包含又有不 ...

  8. POJ 2299-Ultra-QuickSort-线段树的两种建树方式

    此题有两种建树方式! Description In this problem, you have to analyze a particular sorting algorithm. The algo ...

  9. Codeforces Round #442 (Div. 2) E Danil and a Part-time Job (dfs序加上一个线段树区间修改查询)

    题意: 给出一个具有N个点的树,现在给出两种操作: 1.get x,表示询问以x作为根的子树中,1的个数. 2.pow x,表示将以x作为根的子树全部翻转(0变1,1变0). 思路:dfs序加上一个线 ...

随机推荐

  1. SpringMVC+RestFul详细示例实战教程

    一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 <!--conf ...

  2. Unable to find setter method for attribute: 属性名

    tld文件里面的名称和标签内的属性名要一致.

  3. 【js编程艺术】小制作五

    1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...

  4. 《JAVASCRIPT高级程序设计》第二章

    把javascript应用在网页中,需要涉及web的核心语言-html:如何让javascript既能与html共存,又不影响页面的显示效果,经过长时间的讨论.试错,最终的决定是为web增加统一的脚本 ...

  5. [CSS3] 学习笔记-CSS3选择器详解(一)

    1.属性选择器 在CSS3中,追加了3个属性选择器,分别为:[att*=val].[att^=val]和[att$=val],使得属性选择器有了通配符的概念. <!doctype html> ...

  6. intelliJ IDEA创建web工程

    1.创建project,也就是eclipse里的workspace,eclipse里1个工作空间里可以创建多个工程,idea的一个工作空间里只创建1个工程. File -- New -- Projec ...

  7. GIS制图课程目录(持续整理)

    GIS制图课程目录 by 李远祥 由于过去一年都没有进行更新,近期终于抽出时间来进行相关知识的整理,因此,对专项技术进行了不同技术线条的梳理.为了方便阅读,特意整理一下全书的目录结构,希望对读者有帮助 ...

  8. Myeclipese改变背景色

    https://www.baidu.com/s?wd=Myeclipese%E6%94%B9%E5%8F%98%E8%83%8C%E6%99%AF%E8%89%B2&ie=utf-8& ...

  9. 报表学习总结(一)——ASP.NET 水晶报表(Crystal Reports)的简单使用

    一.水晶报表简介 Crystal Reports(水晶报表)是一款商务智能(BI)软件,主要用于设计及产生报表.水晶报表是业内最专业.功能最强的报表系统,它除了强大的报表功能外.最大的优势是实现了与绝 ...

  10. C语言 二维数组复制、清零及打印显示

    #include <stdlib.h> #include <stdio.h> #include <string.h> //二维整型数组打印显示 ],int row, ...