您的位置:首页 > 其它

树链剖分

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)

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: