树链剖分
2015-12-28 13:28
148 查看
前些天提到了GDKOI的事情,严sir说这周六之前要自学一下树链剖分,然后我就去看了一下,这一下就是一周……(某LJ好像看了一周多才搞定)然后ZZX大神讲课的时候我就意识到我的实现方法在细节上严重受到hzwer大神污染……反正大体上是一样的。
感谢hzwer大神提供了代码和详细解答:http://hzwer.com/2543.html
其实树链剖分的意思就是把一棵树里每条边的情况放到线段树上。所谓的剖分就是指把树里面一条条的链分成轻链和重链两类进行操作。
重链的值用线段树维护查询,轻边的值直接查询。
然后的话要DFS2遍,第一遍先求出每个点的深度dep,子树大小size,以及parent(这里的parent[x,i]指点x往上2^i的祖先)
第二遍的话求重链,就是用往下拓展的方式把重链拉出来。选择子树较大的节点继承重链,其余子节点再自己往下拉重链。
然后就用和普通线段树类似的方式维护就可以了,不过比较特殊的一点是其修改方式如下:
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
这里就是我的实现方式(或者说hzwer大神实现方式)的不同之处了,zzx的实现方式是每次把深度较深的点往上靠。我的方式是直接求出lca再往lca上靠……
查询的思路也是一样的。
好吧,上代码:(codevs2460)
感谢hzwer大神提供了代码和详细解答:http://hzwer.com/2543.html
其实树链剖分的意思就是把一棵树里每条边的情况放到线段树上。所谓的剖分就是指把树里面一条条的链分成轻链和重链两类进行操作。
重链的值用线段树维护查询,轻边的值直接查询。
然后的话要DFS2遍,第一遍先求出每个点的深度dep,子树大小size,以及parent(这里的parent[x,i]指点x往上2^i的祖先)
第二遍的话求重链,就是用往下拓展的方式把重链拉出来。选择子树较大的节点继承重链,其余子节点再自己往下拉重链。
然后就用和普通线段树类似的方式维护就可以了,不过比较特殊的一点是其修改方式如下:
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
这里就是我的实现方式(或者说hzwer大神实现方式)的不同之处了,zzx的实现方式是每次把深度较深的点往上靠。我的方式是直接求出lca再往lca上靠……
查询的思路也是一样的。
好吧,上代码:(codevs2460)
type map=record t,next:longint; end; tpoint=^tppoint; tppoint=record l,r,m:longint; num,max:longint; lc,rc:tpoint; end; var n,q,m,i,j,num,x,y,root,k,pa:longint; parent:array[1..30000,0..14]of longint; value,head,dep,size,belong,p:array[0..30000]of longint; vis:array[1..30000]of boolean; edge:array[1..60000]of map; tree:tpoint; s,order:string; function max(a,b:longint):longint; begin if a>b then exit(a) else exit(b); end; procedure swap(var a,b:longint); var t:longint; begin t:=a; a:=b; b:=t; end; procedure insert(s,t:longint); begin inc(m); edge[m].t:=t; edge[m].next:=head[s]; head[s]:=m; inc(m); edge[m].t:=s; edge[m].next:=head[t]; head[t]:=m; end; procedure dfs1(x:longint); var i:longint; begin size[x]:=1; vis[x]:=true; for i:=1 to 14 do begin if dep[x]<1 shl i then break; parent[x,i]:=parent[parent[x,i-1],i-1]; end; i:=head[x]; while i>0 do begin if vis[edge[i].t] then begin i:=edge[i].next; continue; end; dep[edge[i].t]:=dep[x]+1; parent[edge[i].t,0]:=x; dfs1(edge[i].t); inc(size[x],size[edge[i].t]); i:=edge[i].next; end; end; procedure dfs2(x,chain:longint); var i,k:longint; begin k:=0; inc(num); p[x]:=num; belong[x]:=chain; i:=head[x]; while i>0 do begin if (dep[edge[i].t]>dep[x])and(size[edge[i].t]>size[k]) then k:=edge[i].t; i:=edge[i].next; end; if k=0 then exit; dfs2(k,chain); i:=head[x]; while i>0 do begin if (dep[edge[i].t]>dep[x])and(k<>edge[i].t) then dfs2(edge[i].t,edge[i].t); i:=edge[i].next; end; end; function lca(x,y:longint):longint; var t,i:longint; begin if dep[x]<dep[y] then swap(x,y); t:=dep[x]-dep[y]; for i:=0 to 14 do if t and(1 shl i)>0 then x:=parent[x,i]; for i:=14 downto 0 do if parent[x,i]<>parent[y,i] then begin x:=parent[x,i]; y:=parent[y,i]; end; if x=y then exit(x)else exit(parent[x,0]); end; procedure build(var p:tpoint;l,r:longint); begin new(p); p^.l:=l; p^.r:=r; p^.m:=(l+r)div 2; if l=r then begin p^.lc:=nil; p^.rc:=nil; p^.num:=0; p^.max:=0; exit; end; build(p^.lc,l,p^.m); build(p^.rc,p^.m+1,r); p^.num:=0; p^.max:=0; end; procedure update(var p:tpoint;x,y:longint); begin if p^.l=p^.r then begin p^.max:=y; p^.num:=y; exit; end; if x<=p^.m then update(p^.lc,x,y) else update(p^.rc,x,y); p^.num:=p^.lc^.num+p^.rc^.num; p^.max:=max(p^.lc^.max,p^.rc^.max); end; function asknum(p:tpoint;x,y:longint):longint; begin if p=nil then exit(0); if (p^.l=x)and(p^.r=y) then exit(p^.num); if y<=p^.m then exit(asknum(p^.lc,x,y)) else if x>p^.m then exit(asknum(p^.rc,x,y)) else exit(asknum(p^.lc,x,p^.m)+asknum(p^.rc,p^.m+1,y)); end; function askmax(p:tpoint;x,y:longint):longint; begin if p=nil then exit(0); if (p^.l=x)and(p^.r=y) then exit(p^.max); if y<=p^.m then exit(askmax(p^.lc,x,y)) else if x>p^.m then exit(askmax(p^.rc,x,y)) else exit(max(askmax(p^.lc,x,p^.m),askmax(p^.rc,p^.m+1,y))); end; function solve1(x,pa:longint):longint; var res:longint; begin res:=0; while belong[x]<>belong[pa] do begin inc(res,asknum(tree,p[belong[x]],p[x])); x:=parent[belong[x],0]; end; inc(res,asknum(tree,p[pa],p[x])); exit(res); end; function solve2(x,pa:longint):longint; var mx:longint; begin mx:=-maxlongint; while belong[x]<>belong[pa] do begin mx:=max(mx,askmax(tree,p[belong[x]],p[x])); x:=parent[belong[x],0]; end; mx:=max(mx,askmax(tree,p[pa],p[x])); exit(mx); end; begin readln(n); for i: 4000 =1 to n-1 do begin readln(x,y); insert(x,y); end; for i:=1 to n do read(value[i]); num:=0; dfs1(1); dfs2(1,1); build(tree,1,n); for i:=1 to n do update(tree,p[i],value[i]); readln(q); for i:=1 to q do begin readln(s); order:=copy(s,1,2); k:=pos(' ',s); delete(s,1,k); k:=pos(' ',s); val(copy(s,1,k-1),x); delete(s,1,k); val(s,y); if order[1]='C' then begin value[x]:=y; update(tree,p[x],y); end else begin root:=lca(x,y); if order[2]='M' then writeln(max(solve2(x,root),solve2(y,root))) else writeln(solve1(x,root)+solve1(y,root)-value[root]); end; end; end.
相关文章推荐
- 韦东山第三期视频监控编译华美路由器A100固件问题----已经编译通过
- TeamTalk部署教程
- 【杭电2015年12月校赛D】【水题 最小生成树】Happy Value 最小生成树裸题
- ios 字符串大小写转换代码
- 好奇心害死猫——codevs3123超大整数乘法
- Unity调用外部EXE和启动浏览器(手机端也可以启动IE内核)
- Untiy鼠标控制角色转向
- 深入分析JavaWeb Item35 -- 过滤器Filter学习
- POJ1659Frogs' Neighborhood(lavel定理)
- Linux下,强制删除oracle10g安装文件后再重装
- 算法复习——LazyTag
- Unity动态更换外部Texturte和网络文件
- 【后缀数组】[UVA10829]L-Gap substring
- 可能是最简单的感知机算法
- centos7配置postfix dovecot cyrus-sasl foxmail
- ios 字符串加密到md5
- 蓝桥杯 核桃的数量(最小公倍数)
- 高一上学期期中考总结
- MySQL字符集乱码简单讲解
- JQuery判断密码中是否有空格