差分:一维差分,二维差分,树上差分

一维差分

差分概念

对于一个数列 a i a_{i} ai,我们需要维护的数据是“相邻两个数之差”。这种策略是,令 p i = a i − a i − 1 p_i =a_i-a_{i-1} pi=aiai1,即相邻两数的差。我们称数列 p i p_i pi为数列 a 的差分数列。

具体操作

1.处理过程
它可以维护多次对序列的一个区间加上一个数,并在最后询问某一位的数或是多次询问某一位的数。譬如使 [l, r] 每个数加上一个 k,就是 p l = p l + k , p r + 1 = p r + 1 − k p_{l}=p_{l}+k, p_{r+1}=p_{r+1}-k pl=pl+k,pr+1=pr+1k,最后做一遍前缀和。
2.单点求值
就是对这个差分数列 p i p_{i} pi 做一遍前缀和就得到了原来的数列 a i a_{i} ai,即 a i a_{i} ai 相当于 p [ 1 ,   i ] p_{[1,\ i]} p[1, i] 这个前缀和。

举例

1.基操
原数列 9 4 7 5 9
差分数组 9 -5 3 -2 4
差分数组的前缀和 9 4 7 5 9
如果要在
2.区间加等差序列
给 [3, 5] 加上首项为a、公差为 d 的等差数列
a 区间 [l, r]加等差,相当于 p 区间加常数、端点单点修改。即给 p [ l + 1 , r ] p_{[l+1, r]} p[l+1,r] 每一项加上公差d。
目前 a = { 1 , 2 , 3 , 3 , 3 , 3 } a=\left \{ 1,2,3,3,3,3 \right \} a={1,2,3,3,3,3},则对应的差分数列 p = { 1 , 1 , 1 , 0 , 0 , 0 } p=\left \{ 1,1,1,0,0,0 \right \} p={1,1,1,0,0,0}

给 [3, 5] 加上首项为2、公差为 1 的等差数列,及 { 2 , 3 , 4 } \left \{ 2,3,4 \right \} {2,3,4}。那么原数列变为 a = { 1 , 2 , 5 , 6 , 7 , 3 } a=\left \{ 1,2,5,6,7,3 \right \} a={1,2,5,6,7,3},对差分数列变为 p = { 1 , 1 , 3 , 1 , 1 , − 4 } p=\left \{ 1,1,3,1,1,-4 \right \} p={1,1,3,1,1,4}

题目:洛谷P1438 无聊的数列

二维差分

什么是二维差分
我们有一个矩阵,如下图所示。
在这里插入图片描述
根据二维前缀和表示的是右上角矩形的和,由于差分只涉及前面相邻的数(由一维可以推出),并且由前面范围的数相加得到这个位置的数。那么类比二维前缀和和一维差分,可以简单推测出二维差分的公式

p [ i ] [ j ] = a [ i ] [ j ] − a [ i − 1 ] [ j ] − a [ i ] [ j − 1 ] + a [ i − 1 ] [ j − 1 ] p[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1] p[i][j]=a[i][j]a[i1][j]a[i][j1]+a[i1][j1]

如何从差分矩阵得到原矩阵呢?可以参考下面公式

a [ i ] [ j ] = p [ i ] [ j ] + p [ i − 1 ] [ j ] + p [ i ] [ j − 1 ] − p [ i − 1 ] [ j − 1 ] a[i][j] = p[i][j]+p[i-1][j]+p[i][j-1]-p[i-1][j-1] a[i][j]=p[i][j]+p[i1][j]+p[i][j1]p[i1][j1]

举例

比如,我们有一个矩阵 a,如下所示:

1 2 4 3
5 1 2 4
6 3 5 9

那么对应的二维差分矩阵 p 如下:

1  1  2 -1
4 -5 -1  3
1  1  1  2

应用

如果我们要在左上角是 (x1,y1),右下角是 (x2,y2) 的矩形区间每个值都 +a,如下图所示
 在这里插入图片描述

在我们要的区间开始位置(x1,y1)处 +c,根据前缀和的性质,那么它影响的就是整个黄色部分,多影响了两个蓝色部分,所以在两个蓝色部分 -c 消除 +c 的影响,而两个蓝色部分重叠的绿色部分多了个 -c 的影响,所以绿色部分 +c 消除影响。所以对应的计算方法如下:

diff[x1][y1] += c;
diff[x1][y2+1] -=c;
diff[x2+1][y1] -=c;
diff[x2+1][y2+1] += c;

原博客地址

树上差分

树上差分有什么作用?举个例子,如果题目要求对树上的一段路径进行操作,并询问某个点或某条边被经过的次数,树上差分就可以派上用场了。这就是树上差分的基本操作。

树上差分,就是利用差分的性质,对路径上的重要节点进行修改(而不是暴力全改),作为其差分数组的值,最后在求值时,利用dfs遍历求出差分数组的前缀和,就可以达到降低复杂度的目的。

树上差分时需要求LCA.

对点和边的树上差分原理相同,实现略有不同,这里分开来讲。

树上点差分

设将两点u,v之间路径上的所有点权增加x,o=LCA(u,v),o的父亲节点为p,则操作如下:

diff[u]+=x,diff[v]+=x,diff[o]-=x,diff[p]-=x;

怎么样,是不是很简单!原理也很简单,举个例子:

设原树如下,现要将2,3之间路径上的所有点的权值增加3,设原权值均为0。

在这里插入图片描述
则操作后有:
在这里插入图片描述
这样,只要dfs一遍,遍历时统计以每个节点为根的树的节点的权值和,就是当前节点的最终权值! 是不是很厉害

就是差分的思想,这里就不多说了。

树上边差分

思想一样,讲一下操作。

设将两点u,v之间路径上的所有边权增加x,o=LCA(u,v),以每条边两端深度较大的节点存储该边的差分数组,则操作如下:

diff[u]+=x,diff[v]+=x,diff[o]-=2*x;

再举个例子,还是上面那个图 绝对不是我懒

在这里插入图片描述
同样地,只要dfs一遍,遍历时统计以每个节点为根的树的节点的权值和,就是当前节点到父亲节点的边的最终权值了!

是不是很厉害

至于为什么点差分和边差分的操作不一样,很简单,请读者自己思考。

习题:

差分

综合应用题:P1083

树上差分

简单模板题:P3128

综合应用题:P2680
P6869 [COCI2019-2020#5] Putovanje

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值