首页 > 其他分享 >树链剖分 学习笔记

树链剖分 学习笔记

时间:2023-01-08 20:23:05浏览次数:50  
标签:sz log 剖分 int void tr 笔记 son 树链

树链剖分是一种思想,可以用来通过给树中每个点重新编号,从而让树中任意一条路径转化成 \(O(log n)\) 段连续区间(链)。树中任意一条路径均可以变成不超过 \(log n\) 段连续区间。从而把树的问题变成区间的问题(线段树维护)。

核心:
(1)将一棵树转化成一个序列。
(2)将树中路径转化成 \(O(log n)\) 段连续区间。

概念:
(1)重儿子 / 轻儿子:非叶节点,节点个数最多的一个子树的根节点叫做重儿子(多个最大值选一个即可),反之称为轻儿子。
(2)重边 / 轻边:对应重儿子 / 轻儿子,根节点与重儿子连的边叫重边,反之叫轻边。
(3)重链:对应重边,重边构成的链叫重链。

如何将整棵树变成一个序列?dfs 序,优先遍历重儿子(走重链)。

重要结论:

  • 树中的任意一条路径均可拆分成 \(O(log n)\) 个重链,即 \(O(log n)\) 个连续区间。

code

int n, m, w[N], h[N], e[M], ne[M], idx, id[N], nw[N], cnt, dep[N], sz[N], top[N], fa[N], son[N];

struct Tree
{
    int l, r;
    LL add, sum;
}tr[N * 4];

void add(int a, int b){ e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;}

void dfs1(int u, int father, int depth)
{
    dep[u] = depth, fa[u] = father, sz[u] = 1;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == father) continue;
        dfs1(j, u, depth + 1);
        sz[u] += sz[j];
        if (sz[son[u]] < sz[j]) son[u] = j;
    }
}

void dfs2(int u, int t)
{
    id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;
    if (!son[u]) return;
    dfs2(son[u], t);
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa[u] || j == son[u]) continue;
        dfs2(j, j);
    }
}

void pushup(int u){ tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;}

void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if (root.add)
    {
        left.add += root.add, left.sum += root.add * (left.r - left.l + 1);
        right.add += root.add, right.sum += root.add * (right.r - right.l + 1);
        root.add = 0;
    }
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, 0, nw[r]};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

void update(int u, int l, int r, int k)
{
    if (l <= tr[u].l && r >= tr[u].r)
    {
        tr[u].add += k;
        tr[u].sum += k * (tr[u].r - tr[u].l + 1);
        return;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) update(u << 1, l, r, k);
    if (r > mid) update(u << 1 | 1, l, r, k);
    pushup(u);
}

LL query(int u, int l, int r)
{
    if (l <= tr[u].l && r >= tr[u].r) return tr[u].sum;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL res = 0;
    if (l <= mid) res += query(u << 1, l, r);
    if (r > mid) res += query(u << 1 | 1, l, r);
    return res;
}

void update_path(int u, int v, int k)
{
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        update(1, id[top[u]], id[u], k);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    update(1, id[v], id[u], k);
}

LL query_path(int u, int v)
{
    LL res = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        res += query(1, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    res += query(1, id[v], id[u]);
    return res;
}

void update_tree(int u, int k){ update(1, id[u], id[u] + sz[u] - 1, k);}

LL query_tree(int u){ return query(1, id[u], id[u] + sz[u] - 1);}

习题选做:
P1505 【国家集训队】 旅游
P2146 【NOI2015】 软件包管理器
P5773 【JSOI2016】 轻重路径
P8334 【ZJOI2022】 深搜
P2542 【AHOI2005】 航线规划
P2486 【SDOI2011】染色
P2590 【ZJOI2008】 树的统计
P3178 【HAOI2015】 树上操作
P3250 【HNOI2016】 网络
P3258 【JLOI2014】 松鼠的新家
P3313 【SDOI2014】旅行
P3703 【SDOI2017】 树点涂色
P3781 【SDOI2017】 切树游戏
P3833 【SHOI2012】 魔法树
P3976 【TJOI2015】 旅游
P4069 【SDOI2016】 游戏
P4092 【HEOI2016/TJOI2016】 树
P4175 【CTSC2008】 网络管理
P4211 【LNOI2014】 LCA
P4281 【AHOI2008】 紧急集合 / 聚会
P4332 【SHOI2014】 三叉神经树
P4338 【ZJOI2018】 历史
P4427 【BJOI2018】 求和
P4679 【ZJOI2011】 道馆之战

标签:sz,log,剖分,int,void,tr,笔记,son,树链
From: https://www.cnblogs.com/sunruize/p/17035264.html

相关文章

  • 学习笔记——Maven的核心概念之仓库、坐标;maven的依赖管理;Maven中统一管理版本号;Maven
    2023-01-08一、Maven的核心概念1、仓库(1)仓库的分类①本地仓库:为当前计算机提供maven服务②远程仓库:为其他计算机提供maven服务a.私服:架设在当前局域网环境下,为当前局......
  • 读编程与类型系统笔记01_类型简介
    1. 引子1.1. 1999年发射的火星气候探测者号(MarsClimateOrbiter)进入火星轨道的过程中失去联络1.2. 原因1.2.1. Lockheed(洛克希德·马丁公司)开发的一个组件使用磅力......
  • 机器学习 吴恩达 第四章 笔记
    四、多变量线性回归(LinearRegressionwithMultipleVariables)  在本章节,我们要讨论一种新的线性回归形式.这种形式适用于多个变量(或者说多特征量).在我们之前讨论......
  • 外设驱动库开发笔记50:HP203B气压传感器驱动
      在我们的项目中,经常会有需要检测大气压力的时候。这次我们在大气环境监测的过程中用到了HP203B这款气压传感器。所以这一篇中,我们来思考HP203B气压传感器的驱动设计。......
  • 学习笔记:导数
    为了多项式对数函数学的,反正高考也得学,早学晚学都一样然而这篇博客就像我的积累本一样,全是粘贴,没有笔记你别说,乍一看还以为是我写的(......
  • sql注入学习笔记
    一.基础sql语法知识SELECT查询信息SELECT*FROMTABLES查询表中所有列SELECTCOLUMN1,COLUMN2FROMTABLES查询表中具体的列SELECTDISTINCTCOLUMN1FROMTABLES......
  • 爬虫学习笔记
    1.基本步骤 2.案例  -1.爬取指定词条对应的搜索页面    -2.爬取百度翻译的数据   -3.爬取豆瓣排行榜信息(带分析)  获取url和请求方法,url截......
  • Java面试题笔记
    1Hystrix的状态有哪些closed->open:正常情况下熔断器为closed状态,当访问同一个接口次数超过设定阈值并且错误比例超过设置错误阈值的时候,就会打开熔断机制,这时候熔断......
  • 读书笔记_鸟哥的Linux私房菜_基础学习篇_第4版_第4章
    目录目录目录命令行模式下的命令执行命令格式示例基础命令date示例cal示例bc示例热键[TAB]示例[Ctrl]-c示例[Ctrl]-d示例命令求助--help示例man示例命令行模式下的命令......
  • 最短路问题学习笔记
    之前对最短路的认识不是很充分,结合之前的博客来重新总结一下最短路的问题的解法。Floyd算法——小数据杀手相信最先接触的最短路算法就是Floyd算法了,因为他精简的代码实......