前缀和 & 差分
前缀和
定义
前缀和可以简单理解为「数列的前
C++ 标准库中实现了前缀和函数 std::partial_sum
,定义于头文件 <numeric>
中。
例题
有
输入:
5
1 2 3 4 5
输出:
1 3 6 10 15
递推:B[0] = A[0]
,对于 B[i] = B[i-1] + A[i]
。
二维/多维前缀和
多维前缀和的普通求解方法几乎都是基于容斥原理。
比如我们有这样一个矩阵
1 2 4 3
5 1 2 4
6 3 5 9
我们定义一个矩阵
那么这个矩阵长这样:
1 3 7 10
6 9 15 22
12 18 29 45
第一个问题就是递推求
因为同时加了
第二个问题就是如何应用,譬如求
那么,根据类似的思考过程,易得答案为
例题
在一个
基于 DP 计算高维前缀和
基于容斥原理来计算高维前缀和的方法,其优点在于形式较为简单,无需特别记忆,但当维数升高时,其复杂度较高。这里介绍一种基于 DP 计算高维前缀和的方法。该方法即通常语境中所称的 高维前缀和。
设高维空间
其递推关系为
一种实现的伪代码如下:
for state
sum[state] = f[state];
for(i = 0;i <= D;i += 1)
for 以字典序从小到大枚举 state
sum[state] += sum[state'];
树上前缀和
设
然后:
-
若是点权,
路径上的和为 。 -
若是边权,
路径上的和为 。LCA 的求法参见 最近公共祖先。
差分
解释
差分是一种和前缀和相对的策略,可以当做是求和的逆运算。
这种策略的定义是令
性质
的值是 的前缀和,即- 计算
的前缀和
它可以维护多次对序列的一个区间加上一个数,并在最后询问某一位的数或是多次询问某一位的数。注意修改操作一定要在查询操作之前。
譬如使
其中
最后做一遍前缀和就好了。
C++ 标准库中实现了差分函数 std::adjacent_difference
,定义于头文件 <numeric>
中。
树上差分
树上差分可以理解为对树上的某一段路径进行差分操作,这里的路径可以类比一维数组的区间进行理解。例如在对树上的一些路径进行频繁操作,并且询问某条边或者某个点在经过操作后的值的时候,就可以运用树上差分思想了。
树上差分通常会结合 树基础 和 最近公共祖先 来进行考察。树上差分又分为 点差分 与 边差分,在实现上会稍有不同。
点差分
举例:对树上的一些路径
对于一次
其中
可以认为公式中的前两条是对蓝色方框内的路径进行操作,后两条是对红色方框内的路径进行操作。不妨令
边差分
若是对路径中的边进行访问,就需要采用边差分策略了,使用以下公式:
由于在边上直接进行差分比较困难,所以将本来应当累加到红色边上的值向下移动到附近的点里,那么操作起来也就方便了。对于公式,有了点差分的理解基础后也不难推导,同样是对两段区间进行差分。
例题
FJ 给他的牛棚的
FJ 有
需要统计每个点经过了多少次,那么就用树上差分将每一次的路径上的点加一,可以很快得到每个点经过的次数。这里采用倍增法计算 LCA,最后对 DFS 遍历整棵树,在回溯时对差分数组求和就能求得答案了。
习题
前缀和:
- 洛谷 B3612【深进 1. 例 1】求区间和
- 洛谷 U69096 前缀和的逆
- AT2412 最大の和
- 「USACO16JAN」子共七 Subsequences Summing to Sevens
- 「USACO05JAN」Moo Volume S
二维/多维前缀和:
基于 DP 计算高维前缀和:
树上前缀和:
差分:
树上差分:
参考资料与注释
Footnotes
-
南海区青少年信息学奥林匹克内部训练教材 ↩
贡献者:@Zirnc@WenzelTian@Haoshen@Dejia@H-J-Granger@kenlig@llh721113@ksyx@Alpacabla@mgt@Leo@夜轮_NachtgeistW@wuyudi@Margatroid@Chrogeek@邵晨恒@Henry-ZHR@Xiaodai@ouuan@sshwy@Ir1dXD@Alpha1022@ChungZH@P6174
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用