轻重链剖分 学习笔记

本文介绍了轻重链剖分的算法,用于解决树上修改和查询点链上或子树权值的问题。首先讲解了算法的定义,包括重儿子、轻儿子、重边和轻边的概念。接着阐述了算法的实现,包括预处理的两次DFS,以及如何通过线段树进行修改和查询操作。最后讨论了算法的时间复杂度,处理链的时间复杂度为O(logn),处理子树的时间复杂度为O(log2n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

板子题

题目传送门
这道题目要求在树上修改和查询点一条链上或者是一棵子树的点的权值。

算法解析

考虑使用LCA,但是不能使用倍增的解法(倍增只能查询不能修改),所以我们要使用一种新的算法——轻重链剖分。
建议先学完LCA在来看这篇文章。

定义

这里列出一些必要的定义:

  1. 重儿子:子节点最多的一个儿子。
  2. 轻儿子:一个节点的儿子除重儿子之外的儿子。
  3. 重边:一段为重儿子的边。
  4. 轻边:除重边以外的边。
  5. 重链:由重边组成的链,由轻儿子为起点。

实现

预处理

预处理由两次dfs组成。
第一次dfs需要处理以下数组:
f a , s o n , s i z , d fa,son,siz,d fa,son,siz,d 分别代表节点的 父亲,重儿子,子树节点数,深度。
第二次dfs需要处理以下数组:
i d , t o p , a id,top,a id,top,a 分别代表节点的新编号(按照dfs达到的顺序),这个节点所在的重链的顶端,新编号的点权,注意一定要先处理重儿子并且使用dfs。原因后面讲。

修改

怎么修改或者查询一条链的点权呢?
我们可以让更深的点沿着重链向上跳,直到两个点处于同一条重链上就可以了。
然后我们会发现,如果先处理重儿子并且使用dfs的时候,这样一条重链上的节点和一棵子树的节点的编号是连续的,我们就可以使用线段树来解决这个问题了。
而处理一棵子树权值的时候,我们只要将 i d i id_i idi i d i + s i z i − 1 ] id_i+siz_i-1] idi+sizi1] 这段区间进行修改或者是查询就可以了。

因为修改的点的 i d id id 都是连续的,所以我们就可以使用线段树大法来解决了。

复杂度

处理一条链的复杂度是 Θ ( log ⁡ 2 n ) \Theta\left(\log^2n\right) Θ(log2n) ,处理子树的复杂度是 Θ ( log ⁡ n ) \Theta\left(\log n\right) Θ(logn)

代码

这里用递归式线段树来解决这个问题。

#include<cstdio>
#define maxn 100039
#define emaxn 200039
using namespace std;
typedef long long ll;

int n,T,root;
ll MOD;

int head[maxn],n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值