浅谈树链剖分
来源:互联网 发布:mac os x 10.9.5 编辑:程序博客网 时间:2024/06/11 21:29
首先把一个知识摆在前面:倍增。
这是个非常优秀的算法,他普遍应用与何处呢?像树上的倍增求LCA,序列中的倍增RMQ之类的算法,倍增在dp中也有广泛应用,可以大大优化时间和空间。
但是我相信,各位读者都是比本人智商高的人,于是倍增只讲讲一个RMQ。
RMQ有一个很优秀的算法就是DP。这个大家都很熟悉,众所周知,RMQ中多加一个修改操作,那么DP就失去的它的用武之地,也就是说,倍增在这里就不管用了。那么,就引出了重点内容——树链剖分。
树链剖分的目的是对树路径信息维护。将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN)。
但是如何分呢?分成什么呢?
将树中的边分为:轻边和重边
定义siz(x)为以x为根的子树的节点个数。
令v为u的儿子节点中siz值最大的节点,那么边(u,v)被称为重边,树中重边之外的边被称为轻边。
上图节点中的数表示儿子数量。粗边为重边。其余的为轻边。
我们称某条路径为重链,重链是由重边组成。
top[x]表示x所属重链的起点。
x 1 2 3 4 5 6 7 8 9
top[x] 1 1 3 4 5 1 4 1 4
轻边(U,V),siz(V)<=siz(U)/2。从根到某一点的路径上,不超过O(logN)条轻边,不超过O(logN)条重路径。
然后大家就看完了概念,现在我们来考虑如何实现。
数链剖分的过程为2次dfs
第一次:按照定义找出重边、重儿子
第二次:按照优先走重边的原则走出一个dfs序,x在dfs序中的位置记为tree[x],并算出每个点所属重链的起点top[x]。
剖分完之后,每条重链就相当于一段区间,用数据结构(如线段树等)去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可。
如果u和v在同一条重链上,直接用数据结构修改tree[u]至tree[v]间的值或查询答案。
如果u和v不在同一条重链上 一边进行修改,一边将u和v往同一条重链上靠,然后就变成了上面的情况。
具体操作:我们把深度较大的一方x跳到他的fa[top[x]]上,并修改或查询tree[top[x]]~tree[x]
由于一条重链在数据结构中是一段连续的区间,所以直接查询tree[top[x]]~tree[x]是没问题的。
然后就几乎没啦。
证明一下时间复杂度。
一条路径由于被分成logN条重链,每条重链又对数据结构进行一次搜索,所以一次操作的复杂度为O(logN*数据结构的复杂度)。
假如用LCT来维护的话就是O(logN)了。
最后,丢下一道经典例题:
【ZJOI2008】树的统计
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
Input
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
Data Constraint
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
本题显然树链剖分,大家可以把本题作为树链剖分的入门题,开心地虐题把~~~
Code:
uses math;var i,j,k,l,n,m,num,x,y,tot,gs:longint; small,ans:int64; tov,last,next,siz,son,dep,fa,tree,pre,top,f,a,tmax:array[1..800000] of int64; ch:char;procedure maketree(x,st,en:longint);var m:longint;begin if st=en then begin f[x]:=a[pre[st]]; tmax[x]:=a[pre[st]]; end else begin m:=(st+en) div 2; maketree(x*2,st,m); maketree(x*2+1,m+1,en); tmax[x]:=max(tmax[x*2],tmax[x*2+1]); f[x]:=f[x*2]+f[x*2+1]; end;end;procedure change(v,x,l,r,y:longint);var i,j,mid:longint;begin if l=r then begin tmax[v]:=y; f[v]:=y; exit; end; mid:=(r+l) div 2; if x>mid then begin change(v*2+1,x,mid+1,r,y); end else begin change(v*2,x,l,mid,y); end; tmax[v]:=max(tmax[v*2],tmax[v*2+1]); f[v]:=f[v*2]+f[v*2+1];end;procedure findsum(x,st,en,l,r:longint);var m:longint;begin if (st>=l) and (en<=r) then ans:=ans+f[x] else begin m:=(st+en) div 2; if r<=m then findsum(x*2,st,m,l,r) else begin if l>m then findsum(x*2+1,m+1,en,l,r) else begin findsum(x*2,st,m,l,m); findsum(x*2+1,m+1,en,m+1,r); end; end; end;end;procedure findmax(x,st,en,l,r:longint);var m:longint;begin if (st>=l) and (en<=r) then ans:=max(ans,tmax[x]) else begin m:=(st+en) div 2; if r<=m then findmax(x*2,st,m,l,r) else begin if l>m then findmax(x*2+1,m+1,en,l,r) else begin findmax(x*2,st,m,l,m); findmax(x*2+1,m+1,en,m+1,r); end; end; end;end;procedure dfsfd(v,f,d:longint);var i,j,k,l:longint;begin fa[v]:=f; dep[v]:=d; siz[v]:=1; i:=last[v]; while i<>0 do begin if tov[i]<>fa[v] then begin dfsfd(tov[i],v,d+1); siz[v]:=siz[v]+siz[tov[i]]; if (son[v]=0) or (siz[tov[i]]>siz[son[v]]) then son[v]:=tov[i]; end; i:=next[i]; end;end;procedure dfs(v,num:longint);var i,j,k,l:longint;begin inc(gs); tree[v]:=gs; top[v]:=num; pre[tree[v]]:=v; if son[v]=0 then exit; dfs(son[v],num); i:=last[v]; while i<>0 do begin if tov[i]<>fa[v] then begin if tov[i]<>son[v] then begin dfs(tov[i],tov[i]); end; end; i:=next[i]; end;end;function getmax(x,y:int64):int64;var i,j,tx,ty:longint; k:int64;begin tx:=top[x]; ty:=top[y]; k:=small; while tx<>ty do begin if dep[tx]<dep[ty] then begin ans:=small; findmax(1,1,n,min(tree[y],tree[ty]),max(tree[ty],tree[y])); k:=max(k,ans); y:=fa[ty]; ty:=top[y]; end else begin ans:=small; findmax(1,1,n,min(tree[x],tree[tx]),max(tree[tx],tree[x])); k:=max(k,ans); x:=fa[tx]; tx:=top[x]; end; end; if dep[x]>dep[y] then begin ans:=small; findmax(1,1,n,tree[y],tree[x]); k:=max(k,ans); end else begin ans:=small; findmax(1,1,n,tree[x],tree[y]); k:=max(k,ans); end; exit(k);end;function getsum(x,y:int64):int64;var i,j,tx,ty,k:longint;begin tx:=top[x]; ty:=top[y]; k:=0; while tx<>ty do begin if dep[tx]<dep[ty] then begin ans:=0; findsum(1,1,n,min(tree[y],tree[ty]),max(tree[ty],tree[y])); k:=k+ans; y:=fa[ty]; ty:=top[y]; end else begin ans:=0; findsum(1,1,n,min(tree[x],tree[tx]),max(tree[tx],tree[x])); k:=k+ans; x:=fa[tx]; tx:=top[x]; end; end; if dep[x]>dep[y] then begin ans:=0; findsum(1,1,n,tree[y],tree[x]); k:=k+ans; end else begin ans:=0; findsum(1,1,n,tree[x],tree[y]); k:=k+ans; end; exit(k);end;procedure insert(x,y:longint);begin inc(tot); tov[tot]:=y; next[tot]:=last[x]; last[x]:=tot;end;begin readln(n); for i:=1 to n-1 do begin readln(x,y); insert(x,y); insert(y,x); end; for i:=1 to n do begin read(a[i]); end; fillchar(tmax,sizeof(tmax),128); fillchar(f,sizeof(f),0); small:=tmax[1]; dfsfd(1,0,1); dfs(1,1); maketree(1,1,n); readln(m); for i:=1 to m do begin if i=9 then ch:=' '; read(ch); if ch='Q' then begin read(ch); if ch='M' then begin for j:=1 to 3 do read(ch); readln(x,y); writeln(getmax(x,y)); end else if ch='S' then begin for j:=1 to 3 do read(ch); readln(x,y); writeln(getsum(x,y)); end; end else if ch='C' then begin for j:=1 to 6 do read(ch); readln(x,y); change(1,tree[x],1,n,y); a[x]:=y; end; end;end.
说在最后:
树链剖分是一个方法,思路,只要多去找题练习,就可以很好掌握。它的应用范围特别广阔,所以,早学晚学都是可以的~
- 浅谈树链剖分
- 浅谈树链剖分
- 浅谈
- 浅谈树链剖分(每日不间断更新中)
- BZOJ 2243 浅谈树链剖分+线段树
- BZOJ 4034浅谈树链剖分及线段树维护
- 浅谈SOAP
- 浅谈DataSet
- 浅谈SOAP
- 浅谈职业生涯规划
- IPv6浅谈
- 浅谈SOAP
- 浅谈const
- 浅谈职业生涯规划
- 浅谈blog
- 浅谈PM
- 浅谈人生
- 浅谈BOM
- POI技术实现EXCEL的导入导出
- Driver 分层的思想 -- Linux Kernel 内核实现欣赏
- Carbide编辑CP代码中的环境配置及编译
- @EnableWebMvc 与 @EnableAutoConfiguration 的关系
- EU4-33: Sloving an employee problem
- 浅谈树链剖分
- Java中Class类与RTTI
- 手机的唯一识别符
- 第17课
- POJ 1273 Drainage Ditches
- Angular 2基础(一) 环境搭建
- matlab 怎么在直角坐标系中添加最值得数值
- 过滤器和拦截器的区别
- 信息安全第三篇(网络传输的加密与解密)