差分学习笔记

差分

(姗姗来迟的一篇学习笔记)

Part 1 一维差分

P2367 语文成绩

给出一个序列,支持修改,查询最小值。

在不考虑数据结构的情况下,有一种东西,叫差分。

他可以做到 \(O(1)\) 修改,\(O(n)\) 查询。

首先假设有一个序列:\(1,6,8,5,10\)

他的差分数组就是:\(1,5,2,-3,5\)\(d_i=a_i-a_{i-1}\)

如果是要对区间 \([l,r]\) 加上某个数 \(x\) 的话,只要在把 \(d[l]\) 加上 \(x\)\(d[r+1]\) 减去 \(x\) 即可。

原因就是,在修改完以后,我们需要遍历一次序列去更新新的 \(a_i\)\(a_i=a_{i-1}+d[i]\),假设 \(x\) 修改了 \([l,r]\)\(a_{l+1}\) 就必然加上 \(x\),由于 \(d_{l+2}\) 并没有改变,也就是相差的数不变。加上这个数,\(a_{l+2}\) 一样会更新。但是到了 \(a_{r+1}\) 我们就不必加了,所以要减去 \(x\)

\(Code\)

P1083 借教室

题目里边藏了很多细节,稍不注意到就会错过正解。

  1. 一旦遇到第一个不满足的,就直接停止分配。

  2. 按照先后顺序来借。先到先得。

看到第二个性质,不难想到二分查找来判断是否满足条件。

而对于从 \([l,r]\) 中借教室,可以使用差分轻松实现。差分数组保存的是每天的借的教室个数。

而二分的判断闭区间,就是对于 \([1,l]\) 是否可以满足借的原则来进行的一个二分查找 \(l\)

判断内容就是差分,查询的时候看每一天是否满足 \(room[i]\) 要求即可。

\(Code\)

Part 2 二维差分

和二维前缀和大同小异。

回顾一下二维前缀和:

sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]

P3397 地毯

先考虑修改,时间是 \(O(1)\) 的。对四个方向操作即可。

再考虑查询:

通过看查询的步骤,就知道操作的意义了。其实和一维差分的性质是一样的。边界开头就增加,到了边界就减去。

在遍历的时候就是 \(O(n^2)\),即:

d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+a[i][j]

于是就结束了。了解本质即可。

\(Code\)

Part 3 树上差分

前置知识:LCA,可以左转 LCA学习笔记

回顾差分的最基本本质:在头(首位)加上修改的数,尾部减去修改的数,在遍历中就可以实现对这个序列的操作。

树上差分有两种,一种是点差分,另外一种是边差分。

先考虑边差分。

我们设 \(d[i]\) 表示从 \(i\) 到他的父亲的边的修改的值的和

假设我们需要给 \(p\)\(q\) 之间的边加上一个 \(x\)

由于树有两个性质:

  1. 任意两个结点之间有且只有一条路径。
  2. 一个结点只有一个父结点(即只有一条返祖边)。

所以对两点之间的边的修改,就可以拆成\([p,lca(p,q)]\)\([q,lca(p,q)]\) 这两条路径。

于是乎就是数列上的差分了。就是
$ d[p]+=x,d[lca(p,q)] -=x,d[q]+=x,d[lca(p,q)] -=x $。

我们只需要如下操作即可:

\[d[p]+=x,d[q]+=x,d[lca(p,q)] -=2x \]

注意,在计算的时候,是由下往上回溯的,统计的是以 \(u\) 为根的子树的和,如果当前的点 \(u\) 高度大于 \(p\) 且包含 \([lca(p,q),p]\) 内的结点,那么他的子树内必定包含 \([q,lca(p,q)]\) 的点,所以 \(d[lca(q,p)]\) 只会减一次且不会减多。

第二种就是点差分。我们就用 \(d[i]\) 表示当前 \(i\) 的点所增加的值。我们还是增加 \([p,q]\) 间点的路径,我们首先是对 \(d[p]+=x,d[q]+=x\),但是这样的话 \(lca(p,q)\) 就会多加一个 \(x\) ,我们需要减去。但是现在还有一个 \(x\) 没有减去,按照一维差分,所以我们要在 \(lca(p,q)\) 的父亲处减去一个 \(x\)

所以点差分的操作就是:

\[d[p]+=x,d[q]+=x,d[lca(q,p)]-=x,d[fa(lca(q,p)]-=x \]

P8805 机房

树上前缀和模板,拿来练手的,不多说了。

自己写的题解

P3128 [USACO15DEC]Max Flow P

模板题,显而易见的事情,每次对隔间,也就是点 \(p,q\) 进行操作,板子点差分,不讲。

\(Code\)

P3258 松鼠的新家

每次对参观的两个点进行操作,但是要注意,两次操作之间的起始点是不算的。在最后需要减去。注意终点也要减一。

剩下的还是点差分。

\(Code\)

posted @   June_Failure  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示