差分
-
题单:差分入门
-
概念:
差分:两个相邻的数之差。
把原数列进行差分,得到新数列,这是1阶差分。
把新数列再差分,得到2阶差分的数列。
以此类推,进行n次差分后,得到的数列就是n阶差分。
应用:
用于解决有规律的区间问题,
例如区间加等差数列,给(xin[L,R])加上((x - L) * d),
2阶差分下的等差数列就可以转化为普通的差分问题(+1), (-1)。
通常需要找到数列在n阶差分下变成简单差分问题,再进行从(n)到(0)阶用前缀和还原,还要注意(n)阶差分在(1)到(n)阶的影响要消除。
树上差分:
点权:
对(u,v) ,(+1);
对(lca,f(lca)),(-1).
边权:
边记在较深点。
对(u,v) ,(+1);
对(lca),(-1).
- 问题:
下面 (a_{i,j}) 表示 (a) 经过 (i) 次差分后第 (j) 位的数。
区间对([L, R])加上(s, ..., e)的等差数列。
一个等差数列(y = d(x-1) + s),容易发现是一次函数,进行一次差分就变成常数,对常数差分就变成(0)((y''=0))
原数列({1,2,3,4,5})
一次差分({1,1,1,1,1})
二次差分({1,0,0,0,0})
有操作([1,3],s=2,e=4),那么这个等差数列是({2,3,4}),公差(d = 1)
一次差分得到({2,1,1}),这是在一阶差分数组对区间([1,3])加上(2,1,1)
在差分得到({2,-1,0}),发现就能在原数组的二阶差分下,对(a_{2,1}+1),对(a_{2,2} - 1)对 (a_{2,3 + 1} - (2 - 1)).
二阶差分({3,-1,0,-1,0,0})
一阶差分({3,2,2,1,1})
原数组({3,5,7,8,9})
发现多了好多,这是没有消除影响的结果。
这时一阶为({3,2,2,1,1})
在对(a_{2,3 + 1} - (2 - 1))的同时,也要对(a_{1,3+1}- sum), (sum) 为询问操作在一阶差分的区间([1,3])的和(2 + 1 + 1=4)
这时一阶为({3,2,2,1 - 4,1})
还原,原数组({3,5,7,4,5}),即({1+2,2+3,3+4,4,5})。
在本题题解中,也有把这些影响化简的方法,就能只在二阶差分数组操作。
(forall xin[L,R]subset Z, x + inom{x - L + k}{k})
简单的变换(inom{x-L+k}{k} = inom{x-L+k}{x-L})
对于一个组询问((L,R,k)),就加(inom{k}{0}),(inom{k + 1}{1}),(...),(inom{k + R - L}{R - L}).
在杨辉三角里,这就是一条起点是((k, 0))终点是((k + R - L, R - L))的线段,正好是(45)°。
我们知道
移项得到
发现上面
与这条式子很像。
就把它差分一次,得到
这个
这样换一下就漂亮多了:
再差分:
那么差分了(j)次,就得到:
当差分了(k + 1)次,
这时所有数都为(0),再差分也没有意义了。
-
考虑经过(k + 1)次差分后,得到全0的数列。
-
假如给第(L)数也就是这个数列的第一个数(+1)。
这里(inom{k - k}{0} = 1)。
到了第二个数,求前面两个数的和,((1 + inom{k-(k + 1)}{0}) + inom{k-(k+1) + 1}{1} = inom{k - k}{0} + inom{k-k}{1}=inom{k - k + 1}{1})这就是(K)次差分数组的第二个数。
-
以此类推,只要给(a[k+1][L] +1),就能推出(a[k][L...N])。
那么在(R+1)位置(-1),就能不改变(R+1)后面的位置了,即算出了 (a[k][L...R])。
-
这样算就发现(a[k - 1][R...N])多了,推出上一阶的差分数组时要考虑有没有算多,考虑 (K) 次差分在 (K - 1) 次差分的影响,这就是在 (K - 1) 次差分的 (R+1) 位置,减去这次加入的数列([L,R])在(K)次差分下的和。
总的来说,就是对
$$forall K in [1,k + 1], a[K][R+1] - sum$$这个数列在(K)次差分下为(inom{k - K}{0},inom{k + 1 - K}{1},...,inom{k + R - L - K}{R - L}).
即
$$a[K][R + 1] - (inom{k - K}{0} + inom{k + 1 - K}{1} + ... + inom{k + R - L - K}{R - L})$$
通过证明,
$$inom{k - K}{0} + inom{k + 1 - K}{1} + ... + inom{k + R - L - K}{R - L} = inom{K + R - L - K + 1}{R - L} $$感性理解一下,
在杨辉三角里,就是一条起点是((k, 0))终点是((k + R - L, R - L))的线段,
[inom{k}{0}=inom{k + 1}{0} = 1 ]这个式子相当于把起点((k,0))移到((k + 1, 0)),
再通过
[inom{k}{i}+inom{k}{i + 1} = inom{k + 1}{i + 1} ]这个式子,把这两个点合成((k + 2,1)),在与((k+2,2))合成((k + 3,2))......最后就合成到
[inom{K+R-L-K+1}{R-L} ] -
所以,对(forall K in [1,k + 1], a[K][R+1] - inom{K+R-L-K+1}{R-L})。
最后就是从(K+1)次差分开始,第(i)次差分通过前缀和,得到(i - 1)的差分,最后得到原数组啦。
CF上用C++14还要把用来差分的数组清零,不然有奇怪的值?
在(O(log n))的时间内,知道了二阶差分,求出原序列某一位。
求原序列的(x)位,
(c)为二阶差分,(b)为一阶差分,那么(b_i = sum_{j=1}^{i}c_j)。
考虑(c_j)会被(a_x)计算几次,首先(c_j)会对(b_j)及以后的(b)产生贡献,
其中贡献到(a_x)的(b)有(b_j)到(b_x),因此(a_x)被贡献((x - j + 1))次
这两个和式都能用树状数组算出。
二维差分。
平面求和,平面修改。
同上题差不多的做法。
差分定义为
和二维前缀和相同。
求a的((1,1))到((x,y))的和。
考虑差分(d_{i,j})的贡献,只有(a_{k,z}|kin[i,x],zin[j,y])算入(d_{i, j})。
那么(d_{i,j})被计算((x-i+1)(y-j+1))次.
用四个二维树状数组记录(d_{i,j},i imes d_{i,j},j imes d_{i,j},i imes j imes d_{i,j})
时间复杂度(O(qlog^2n))