Intro to HLD

buaa prime21

树上的路径询问

区间上的RMQ!                    RMQ上树?

区间上的求和!                     求和上树?

区间上的gcd!                       gcd上树?

区间翻转!                             翻转上树?

 

 

猴子?                                     猴子上树?

heavy-light-decomposition

size:子树大小

重儿子:节点所有儿子中size最大的一个

重边:(heavy edge)每个节点与其重儿子的边

轻边:(light edge)节点与重儿子以外的儿子的边

重链:(heavy path)由重边组成的一条链

算法流程-预处理

dfs1:求出如下信息fa,size,son,deep

         其中son表示一个节点的重儿子

dfs2:top--该点所属重链中deep最小的点

         idx--该点属于第idx条重链

         idy--该点为重链重深度第idy小的

int num_invl;
int idx[N];
int idy[N];
int top[N];
void dfs2(node p){
    if (have_son(p)){
        top[son[p]]=top[p];
        idy[son[p]]=idy[p]+1;
        idx[son[p]]=idx[p];
        dfs2(son[p]);
    }
    for (v:p的所有儿子)
    if (v!=son[p])
    {
        top[v]=v;
        num_invl++;
        idx[v]=num_invl;
        idy[v]=1;
        dfs2(v)
    }
}

算法流程-链操作

void opt(node u,v){
    node fu=top[u],fv=top[v];
    while (fu!=fv){
        if (deep[fu]<deep[fv]){
            swap(fu,fv); swap(f,v);
        }
        operation(idx[fu],idy[fu],idy[u]);
        u=fa[fu];
        fu=top[u];
    }
    if (deep[u]<deep[v]) swap(u,v);
    operation(idx[u],idy[v],idy[u]);
}

opt(u,v)实现了从树上u,v两点间所有节点进行某种操作

算法流程-预处理算法的改进

观察dfs2可知,一条重链在dfs2的dfs序中常常是连续的一段,为了简化代码复杂度,我们不需要记录idx,idy只需要记该点在此dfs序中的位置即可

int df_num;
int pos[N];
int top[N];
void dfs2(node u){
    pos[u]=++df_num;
    if (have_son(u)){
        top[son[u]]=top[u];
        dfs2(son[u]);
    }
    for (v: u的所有儿子)
    if (v!=son[u]){
        top[v]=v;
        dfs2(v);
    }
}

算法流程-链操作的改进

同理可以改写链操作

void opt(node u,v){
    node fu=top[u],fv=top[v];
    while (fu!=fv){
        if (deep[fu]<deep[fv]){
            swap(fu,fv); swap(f,v);
        }
        operation(pos[fu],pos[u]);
        u=fa[fu];
        fu=top[u];
    }
    if (deep[u]<deep[v]) swap(u,v);
    operation(pos[v],pos[u]);
}

改进前和改进后并无本质的区别,改进后代码复杂度更小一些,改进前的写法便于理解,便于思考从本质上处理问题

时间复杂度证明

预处理阶段:每个点在两个dfs中恰好被访问一次O(N)

剖分后的树有一下两个性质:

1.(v,u)为一条轻边,size[v]>size[u]*2

2.从根到某一点的路径经过轻边和重链的个数都不大于O(logN)

询问阶段:两个点到LCA的路径上经过的轻边和重链的个数都不大于O(logN),设在重链上询问操作复杂度为O(Q)

故总复杂度:O(N)-O(QlogN)

树链剖分的意义

以一个log的代价在树上推广若干数据结构和算法

Easy

给定一棵树,依次给出N-1条带权边

支持以下两种操作:

1.CHANGE i ti : 将第i条边的边权改为ti

2.QUERY a b :求a到b的路径中边权最大的边

hint:边操作?父边?

Medium-Easy

给定一颗树,一开始树上所有节点都为白色,支持以下两种操作:

1. 0 i 改变第i个节点的颜色(由黑变白,由白变黑)

2. 1 v 询问从根到v上第一个黑色节点的位置,如果不存在输出-1

sgt or heap

Intro to HLD

By prime21

Intro to HLD

  • 934