树链剖分学习笔记

首先我们有一颗树每个点(或者边)有权值,我们要做的就是询问两个点之间路径上各点(边)权值的最大、最小,权值和(就是线段树能干的),然后我们还要支持在线更改任意节点(边)的权值。

  我们要做的是轻重链剖分,首先我们看几个定义

  size:和SBT里的一样,size[i]为以该点为根节点的子树一共有几个节点。

  重儿子:一个节点当不为叶子节点的时候有且只有一个重儿子,重儿子为该点的儿子中size最大的,有多个最大时任选一个。

  重链:由根节点开始,每个点每次都访问自己的重儿子,一直访问到叶子节点,就组成了一条重链

  那么对于一个点的非重儿子来说,以他为根节点,可以重新访问出一条重链

  如图所示,用红色的线画出的为重链,其中6号点自己为一条重链,那么对于每条重链,我们需要记下他的顶标top,就是该重链中深度最小的节点的标号

  比如链1-3-4-9-10,的top为1,链2-8的top为2。

  重链几个明显的性质就是互不重合且所有重链覆盖所有点,重链之间由一条不在重链上的边(我们称作轻边)连接,然后对于每一条重链来说,我们定义他的深度,顶标为根节点的重链的深度为1,顶标的父亲在深度为x的重链上,那么该重链深度为x+1,如图链1-3-4-9-10的深度为1,链2-8,链5-7的深度为2,链6的深度为3。

那么我们首先DFS,可以求出每个点的size,然后再深搜一遍可得到每个点的top,和处理出每一条链

复制代码
procedure make(x,t,depth:longint);//x代表当前节点,t代表当前重链的顶标,detph代表该重链的深度

var

begin

if max_son[x]<>0 then make(max_son,top,depth);

q:=last[x];

while q<>0 do

begin

    p:=other[q];

    if (not flag[p]) and (p<>max_son[x]) then

    begin

        flag[p]:=true;

        make(p,p,depth+1);

    end;

    q:=pre[q];

end;

end.

复制代码
  那么我们现在有了所有的重链,覆盖每一个点,然后我们要处理的问题是两点之间的最值等问题。

  是不是有些像线段树,假设我们需要求一条重链上的最大值,那么我们需要将重链存进线段树,且重链上的所有点的编号是连续的(区间),那么我们要对所有的点以深搜序重新编号(make的时候顺便搞一下就好了),那么我们可以用线段树来存树上点的值(边儿的也一样,可以将边下放到点),这样对于在同一条重链上的点我们就可以在logn的时间里求出值了,然后对于不同链上的点,我们先给他们升到同一深度上的链,同时更新答案,然后做就好了(有点类似于倍增,就是今年noip Day1 T3,其实内道题用

树链剖分也行,应该早点学啊啊啊啊)至于每个点的权值修改就完全是线段树的事儿了。

第一次写,代码不是很好

复制代码
//By BLADEVIL
type
rec =record
sum, max :longint;
left, right :longint;
end;

var
n :longint;
pre, other :array[0..60010] of longint;
last, key :array[0..30010] of longint;
l :longint;
father, size :array[0..30010] of longint;
flag :array[0..30010] of boolean;
max_son :array[0..30010] of longint;
tot :longint;
num :array[0..30010] of longint;
dep, top :array[0..30010] of longint;
t :array[0..200010] of rec;
a :array[0..30010] of longint;

function max(a,b:longint):longint;
begin
if a>b then max:=a else max:=b;
end;

procedure swap(var a,b:longint);
var
c :longint;
begin
c:=a; a:=b; b:=c;
end;

procedure connect(x,y:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
end;

procedure dfs(x:longint);
var
p, q :longint;

begin
q:=last[x];
size[x]:=1;
while q<>0 do
begin
p:=other[q];
if not flag[p] then
begin
father[p]:=x;
flag[p]:=true;
dfs(p);
inc(size[x],size[p]);
if size[max_son[x]]

你可能感兴趣的:(树链剖分)