前缀和/差分

1. 前缀和

\(\mathcal{O}(n)\) 预处理,多次 \(\mathcal{O}(1)\) 查询。

1.1 一维前缀和

给你一个 \(n\) 个数的序列 \(a\),多次查询 \(l \sim r\) 的和。

维护 \(b_i=\sum\limits_{i=1}^{i} a_i\),查询区间 \(l \sim r\) 的和就是 \(b_r-b_{l-1}\)

1.2 二维前缀和

给你一个 \(n\)\(m\) 列的矩阵 \(a\)。接下来有 \(q\) 次查询,给定参数 \(x_1,y_1,x_2,y_2\)。请输出以 \((x_1, y_1)\) 为左上角, \((x_2,y_2)\) 为右下角的子矩阵的和。

\(b_{i,j}\)\((1,1)\sim (i,j)\) 这个矩阵的和,由容斥原理,可得递推式 \(b_{i,j}=b_{i-1,j}+b_{i,j-1}-b_{i-1,j-1}+a_{i,j}\)

如果要求 \((x_1,y_1)~(x_2,y_2)\) 的矩阵和,那么 \(ans=b_{x_2,y_2}-b_{x_1-1,y_2}-b_{x_2,y_1-1}+b_{x_1-1,x_2-1}\)

2. 差分

支持 \(\mathcal{O}(1)\) 修改,最后 \(\mathcal{O}(n)\) 查询。

1.1 一维差分

给你一个 \(n\) 个数的序列 \(b\),每次操作令 \(l \sim r\) 集体加上 \(v\),最后求序列 \(a\)

\(a_i=\left\{ \begin{array}{} 0 & i=1 \\ b_i-b_{i-1} & i>1 \end{array}\right.\),令 \(l \sim r\) 集体加上 \(v\) 就是 \(a_l+v\)\(a_{r+1}-v\),最后对 \(a\) 做一遍前缀和就得到了最终结果,这是因为前缀和和差分是互逆运算。

1.2 二维差分

给你一个 \(n\)\(m\) 列的矩阵 \(b\)\(q\) 次操作,每次给定参数 \(x1,y1,x2,y2,v\),将子矩阵 \((x_1,y_1)\sim (x_2,y_2)\) 加上 \(v\),最后输出矩阵 \(b\)

由于前缀和和差分是互逆运算,设 \(a\)\(b\) 的差分数组,对前缀和的递推式做代数变换可得 \(a_{i,j}=b_{i,j}+b_{i-1,j-1}-b_{i-1,j}-b_{i,j-1}\)

将子矩阵 \((x_1,y_1)\sim (x_2,y_2)\) 加上 \(v\),其实就等价于

\[\left\{ \begin{array}{} a_{x_1,y_1}+v \\ a_{x_2+1,y_1}-v \\ a_{x_1,y_2+1}-v \\ a_{x_2+1,y_2+1}+v \end{array}\right. \]

最后对于 \(a\) 数组做一遍前缀和就可以得到 \(b\) 数组了。

二维前缀和/差分看起来很麻烦但其实画个图很好理解。

posted @ 2024-10-08 20:12  zhuluoan  阅读(13)  评论(0)    收藏  举报