ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树链剖分学习笔记

2022-04-28 22:04:34  阅读:159  来源: 互联网

标签:重链 剖分 int 笔记 son fx id 树链 节点


树链剖(pōu)分

定义

树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。

树链剖分有多种形式,如重链剖分、长链剖分等,通常说的树链剖分指重链剖分。

重链剖分

首先给出一些定义:

  • 重子节点:所有子节点中子树大小最大的子节点

  • 轻子节点:除重子节点的其它子节点

  • 重边:从这个节点连到重子节点的边

  • 轻边:从这个节点到其它子节点的边

  • 重链:将若干条重边相连得到的链

(图源:oi-wiki)

跑两个 dfs ,第一个跑出来子树大小,深度,父节点和重子节点,第二个 dfs 优先扩展重子节点,记录新编号和新点权,这样能保证先剖出来的一定是重链。

int hson[MAXN], // 重子节点
    fa[MAXN], // 父节点
    cnt[MAXN], // 子树大小
    dep[MAXN], // 深度
    val[MAXN], // val[i]表示初始编号i的点的点权
    top[MAXN], // 所在链的顶
    id[MAXN], // 新编号(dfn序)
    a[MAXN]; // 新编号为i的点的点权
void dfs(int u,int f)
{
    cnt[u]=1;
    for(auto son:Tree[u])
    {
        if(son==f) continue;
        dep[son]=dep[u]+1;fa[son]=u;
        dfs(son,u);cnt[u]+=cnt[son];
        if(cnt[son]>cnt[hson[u]]) hson[u]=son;
    }
}
void dfs1(int u,int f,int t)
{
    id[u]=++tot;a[tot]=val[u];top[u]=t;
    if(hson[u]) dfs1(hson[u],u,t);
    for(auto son:Tree[u]) if(son!=hson[u]&&son!=f) dfs1(son,u,son);
}

重链剖分的性质

  1. 树上每个节点属于且仅属于一条重链

  2. 若 \((u,v)\) 是一条轻边,那么 \(size(v)<size(u)/2\)。

  3. 从根结点到任意结点的路所经过的轻重链的个数必定都小于 \(\log_2n\)。

因此,每向下走一条轻边时,子树大小都至少会除以 \(2\),所以对于树上任意一条路径最多会经过 \(\log_2n\) 条重链。

  1. 子树中的 \(id\) ,也就是 \(dfn\) ,一定是连续的。

一些简单操作

LCA

每次把重链顶深度较大的点向上跳重链,如果两个点在同一条链上,就直接返回深度更小的。时间复杂度 \(O(\log_2n)\)。

int lca(int x,int y)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
        x=fa[fx],fx=top[x];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}

路径上的点权修改

过程和求 LCA 类似,由于每一条重链上的 dfn 值都是连续的,可以用线段树修改,在向上跳的过程中把每条重链都修改了,最后修改剩余部分。时间复杂度 \(O(\log_2^2n)\)。

void update_chain(int x,int y,int k)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
        update(1,1,tot,id[fx],id[x],k);
        x=fa[fx],fx=top[x];
    }
    if(id[x]>id[y]) swap(x,y);
    update(1,1,tot,id[x],id[y],k);
}

路径上的点权和查询

在向上跳的时候答案加上每条重链的和,最后加上剩余部分。

int query_chain(int x,int y)
{
    int res=0,fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
        res+=query(1,1,tot,id[fx],id[x]);
        x=fa[fx],fx=top[x];
    }
    if(id[x]>id[y]) swap(x,y);
    res+=query(1,1,tot,id[x],id[y]);
    return res%mod;
}

例题

CF593D Happy Tree Party

题面传送门

题解传送门

CF916E Jamie and Tree

题面传送门

题解传送门

标签:重链,剖分,int,笔记,son,fx,id,树链,节点
来源: https://www.cnblogs.com/lxy-2022/p/shu-lian-pou-fen.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有