关于使用lazytag的线段树两种查询方式的比较研究
说到线段树,想来大家并不陌生——最基本的思路就是将其规划成块,然后只要每次修改时维护一下即可。
但是尤其是涉及到区间修改时,lazytag的使用往往能够对于程序的质量起到决定性作用(Ex:一般JSOI2008左右的线段树题目,如果有区间修改的话,那么假如普普通通的一个个修改的话,那么一般30分左右,甚至更少;而有了神奇的lazytag,只要别的地方写的还算基本到位,一般就Accept了)
lazytag的基本思想也就是在需要修改的区间打上标记,然后下次动态维护标记和真正值之间的关系,然后查询或者下一个修改操作涉及此区间时,进行进一步维护。
于是,此时就存在两种不同的查询操作了(此处以BZOJ1798为例)
方案一:当查询过程中,遇到了带有标记的点,则将其记录下来(即并入综合的修改参数里面),然后当刚好找到合适区间是,再操作之
function cal(z,x,y,l,r:longint;d:vet):int64;inline;
var d1:vet;
begin
if l>r then exit();
d1:=merge(b[z],d);
if (x=l) and (y=r) then exit(((a[z]*d1.a0) mod p+(d1.a1*((r-l+) mod p)) mod p) mod p);
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);
end;
这个方案在操作时,实际上并没有动任何的标记,直接通过现有的标记求出了值
方案二:查询过程中遇到标记点的话,则将其扩展下去,保证一路下来都不存在标记点,然后到地方了之后直接返回数值
function cal(z,x,y,l,r:longint):int64;inline;
begin
if l>r then exit();
ext(z,x,y);
if (x=l) and (y=r) then exit(a[z]);
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);
end;
附:ext操作和merge操作
function merge(d1,d2:vet):vet;inline;
var d3:vet;
begin
d3:=d1;
d3.a0:=d3.a0 mod p;d3.a1:=d3.a1 mod p;
d2.a0:=d2.a0 mod p;d2.a1:=d2.a1 mod p;
d3.a0:=(d3.a0*d2.a0) mod p;
d3.a1:=((d3.a1*d2.a0) mod p+d2.a1) mod p;
exit(d3);
end;
procedure ext(z,x,y:longint);inline;
begin
a[z]:=((a[z]*b[z].a0) mod p+(b[z].a1*((y-x+) mod p)) mod p) mod p;
b[z*]:=merge(b[z*],b[z]);
b[z*+]:=merge(b[z*+],b[z]);
b[z].a0:=;b[z].a1:=;
end;
此方法比较直观,比较好想,但是看样子好多标记其实被操作了
好了,现在看下时间对比:(注:此两个程序中除了cal函数不一样其他均一样)
方案一:
方案二:(这个里面方案一的cal函数是通过{}注释掉的,所以代码会多出来那么些)
空间上差不多(phile:这不显然的么呵呵呵),时间上方案一要快,原因其实还是因为方案一并没有涉及到修改标记的操作,而方案二涉及了,而且尤其对于tag很密集的树,操作更是会较为复杂。还有方案二虽然更加直观易想,但是代码其实并没有缩减,两者代码复杂度几乎一样。所以综合而言,方案一更加划算么么哒
下面附上BZOJ1798代码
/**************************************************************
Problem:
User: HansBug
Language: Pascal
Result: Accepted
Time: ms
Memory: kb
****************************************************************/ type
vet=record
a0,a1:int64;
end;
var
i,j,k,l,m,n,a2,a3,a4:longint;
p:int64;
a,c:array[..] of int64;
b:array[..] of vet;
d,d1:vet;
procedure built(z,x,y:longint);inline;
begin
if x=y then
a[z]:=c[x] mod p
else
begin
built(z*,x,(x+y) div );
built(z*+,(x+y) div +,y);
a[z]:=(a[z*]+a[z*+]) mod p;
end;
b[z].a0:=;b[z].a1:=;
end;
function max(x,y:longint):longint;inline;
begin
if x>y then max:=x else max:=y;
end;
function min(x,y:longint):longint;inline;
begin
if x<y then min:=x else min:=y;
end;
function merge(d1,d2:vet):vet;inline;
var d3:vet;
begin
d3:=d1;
d3.a0:=d3.a0 mod p;d3.a1:=d3.a1 mod p;
d2.a0:=d2.a0 mod p;d2.a1:=d2.a1 mod p;
d3.a0:=(d3.a0*d2.a0) mod p;
d3.a1:=((d3.a1*d2.a0) mod p+d2.a1) mod p;
exit(d3);
end;
procedure ext(z,x,y:longint);inline;
begin
a[z]:=((a[z]*b[z].a0) mod p+(b[z].a1*((y-x+) mod p)) mod p) mod p;
b[z*]:=merge(b[z*],b[z]);
b[z*+]:=merge(b[z*+],b[z]);
b[z].a0:=;b[z].a1:=;
end;
function op(z,x,y,l,r:longint;d:vet):int64;inline;
var
a3,a4:int64;
begin
if l>r then exit();
ext(z,x,y);
if (x=l) and (y=r) then
begin
b[z]:=d;
exit(((a[z]*((b[z].a0-) mod p)) mod p+(b[z].a1*((r-l+) mod p)) mod p) mod p);
end
else
begin
a3:=op(z*,x,(x+y) div ,l,min(r,(x+y) div ),d);
a4:=op(z*+,(x+y) div +,y,max(l,(x+y) div +),r,d);
a[z]:=(a[z]+(a3+a4) mod p) mod p;
exit((a3+a4) mod p);
end;
end;
{function cal(z,x,y,l,r:longint;d:vet):int64;inline; //方案一
var d1:vet;
begin
if l>r then exit(0);
d1:=merge(b[z],d);
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);
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);
end; }
function cal(z,x,y,l,r:longint):int64;inline; //方案二
begin
if l>r then exit();
ext(z,x,y);
if (x=l) and (y=r) then exit(a[z]);
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);
end; function modd(x:int64):int64;inline;
begin
if x>= then exit(x mod p);
modd:=((abs(x) div p+)*p+x) mod p;
end; begin
readln(n,p);
for i:= to n do read(c[i]);
readln;
built(,,n);
readln(m);
for i:= to m do
begin
read(j);
case j of
:begin
readln(a2,a3,a4);
d.a0:=a4;d.a1:=;
op(,,n,a2,a3,d);
end;
:begin
readln(a2,a3,a4);
d.a0:=;d.a1:=a4;
op(,,n,a2,a3,d);
end;
:begin
readln(a2,a3);
writeln(modd(cal(,,n,a2,a3)));
end;
end;
end;
end.
关于使用lazytag的线段树两种查询方式的比较研究的更多相关文章
- ZOJ-1610 线段树+两种查询方法(弥补我线段树区间填充的短板)
ZOJ-1610 线段树+两种查询方法(弥补我线段树区间填充的短板) 题意 题意:给一个n,代表n次操作,接下来每次操作表示把[l,r]区间的线段涂成k的颜色其中,l,r,k的范围都是0到8000 这 ...
- codevs 2216 线段树 两种更新方式的冲突
题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决 ...
- easyui datagride 两种查询方式
easyui datagride 两种查询方式function doReseach() { //$('#tt').datagrid('load', { // FixedCompany: $('.c_s ...
- HashMap两种遍历方式的深入研究
转自:http://swiftlet.net/archives/1259 HashMap的遍历有两种方式,如下所示:第一种利用entrySet的方式: 1 2 3 4 5 6 7 Map map ...
- js的两种查询方式 LHS and RHS
为了进一步理解,我们需要多介绍一点编译器的术语.编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过查找变量 a 来判断它是否已声明过.查找的过程由作用域进行协助,但是引擎执行怎样的查找,会影响 ...
- mysql查询字段类型为json时的两种查询方式。
表结构如下: id varchar(32) info json 数据: id = info = {"age": "18","di ...
- POJ 3225 线段树区间更新(两种更新方式)
http://blog.csdn.net/niuox/article/details/9664487 这道题明显是线段树,根据题意可以知道: (用0和1表示是否包含区间,-1表示该区间内既有包含又有不 ...
- POJ 2299-Ultra-QuickSort-线段树的两种建树方式
此题有两种建树方式! Description In this problem, you have to analyze a particular sorting algorithm. The algo ...
- 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序加上一个线 ...
随机推荐
- 数据库基础-INDEX
http://m.oschina.net/blog/10314 一.引言 对数据库索引的关注从未淡出我的们的讨论,那么数据库索引是什么样的?聚集索引与非聚集索引有什么不同?希望本文对各位同仁有一定的帮 ...
- Refused to set unsafe header "Connection"
参考 http://stackoverflow.com/questions/7210507/ajax-post-error-refused-to-set-unsafe-header-connectio ...
- overflow:hidden 你所不知道的事
overflow:hidden 你所不知道的事 overflow:hidden这个CSS样式是大家常用到的CSS样式,但是大多数人对这个样式的理解仅仅局限于隐藏溢出,而对于清除浮动这个含义不是很了解. ...
- 字体图标 轻量级 Font Awesome
今天呢,来推荐一款请轻量级 字体图标框架.Font Awesome 用法与bootstrap相似 打开网址.download下载,然后打开取到这两个,下载点这里,这个博客弄的挺好的. 找到exampl ...
- iOS Foundation框架 -1.常用结构体的用法和输出
1.安装Xcode工具后会自带开发中常用的框架,存放的地址路径是: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.plat ...
- javascript学习-类型判断
javascript学习-类型判断 1.类型判断的的武器 javascript中用于类型判断的武器基本上有以下几种: 严格相等===,用来判断null,undefined,true,false这种有限 ...
- ZooKeeper配额
ZooKeeper可以在znode上设置配额限制.如果超出了配置限制,ZooKeeper将会在log日志中打印WARN日志.如果超出配额限制,并不会停止行为操作. ZooKeeper的配额是存储在/z ...
- [MongoDB] - mongod.exe参数详解
mongod.exe是启动mongodb的命令,我们可以通过mongod --help来查看帮助文档.下面是各个参数的对应中文解释.<基于Mongo3.0.5> 通用参数选项 -h/--h ...
- JavaWeb验证码的使用
在Java Web开发中,我们经常需要使用到验证码功能,一般情况下,我们可以将产生的验证码保存到服务器端中的session中,这种方式中,是使用服务器来保证验证码的功能.另外,我们也可以采用js产生验 ...
- 自动化测试 -- 通过Cookie跳过登录验证码
之前写过一篇博客:自动化测试如何解决验证码的问题. http://www.cnblogs.com/fnng/p/3606934.html 介绍了验证码的几种处理方式,最后一种就是通过Cookie跳转过 ...