树链剖分总结

【介绍】
树链剖分,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、SBT、splay、线段树等)来维护每一条链。

【定义】
树链剖分将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN)。
其实质是一些数据结构/算法在树上的推广

树链剖分将一棵树中的边分成重边和轻边。

重边的定义是某一节点与其子节点中size(size表示以某一节点为根的子树的大小)大小最大的子节点的边。

轻边的定义是除重边外的所有边。

重链的定义是一段重边连起来后形成的一条链

【步骤】
Ps:
定义一些数组:
fa[x]表示x节点的父节点。
s[x]表示以x节点为根节点的子树的大小
sonH[x]表示x节点的重儿子(对于x与其子节点相连的重边,重儿子就是重边所连接的子节点)。
dep[x]表示x节点在树中的深度。
top[x]表示x节点沿重边向上所能达到的深度最小的节点。
id[x]表示x节点在树中的编号。
who[x]表示编号为x的节点。

首先先dfs遍历一遍树以获取fa,s,sonH,dep的信息。

void Dfs(int x)//这部分比较容易看懂,不多说。
{
    s[x]=1; dep[x]=dep[fa[x]]+1;
    for (int j=lnk[x]; j; j=nxt[j])
     if (son[j]!=fa[x])
     {
        fa[son[j]]=x;
        Dfs(son[j]);
        s[x]+=s[son[j]];
        if (s[son[j]]>s[sonH[x]]) sonH[x]=son[j];
     }
}

然后根据重边优先的规则再遍历一遍树,以获取top,id,who的信息。

void HLD(int x,int lst)//这部分也比较容易看懂,不多说。
{
    top[x]=lst; who[++tot]=x; id[x]=tot;
    if (sonH[x]) HLD(sonH[x],lst);
    for (int j=lnk[x]; j; j=nxt[j])
     if (son[j]!=fa[x]&&son[j]!=sonH[x]) HLD(son[j],son[j]);
}

修改或查询操作:
1、查询或修改一个点的权值
根据其编号直接在数据结构中修改或查询就行了。

2、修改路径上的权值
①若区间两端的点在同一条重链上
直接用数据结构修改或查询值。

②若区间两端的点不在同一条重链上
将区间划分成好几段重链,每条重链的修改或查询就变成了情况①。

伪代码:

int Work(int x,int y)
{
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        这里进行区间id[top[x]]~id[x]的修改或查询的操作。//top[x]的id必定小于x的id
        x=fa[top[x]];
    }
    if (id[x]>id[y]) swap(x,y);//让x,y中的id小的在前,id大的在后。
    这里进行区间id[x]~id[y]的修改或查询的操作。
    查询(修改不用):return 答案;
}

【例题】
bzoj1036

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值