差分种种

written by oneman233
2019-08-19

差分,在对区间进行修改时候可以使用的一种trick。

可以做到$O(1)$修改,$O(n)$统计答案,即某个区间被累加了几次。

一维差分

区间$[l,r]$全部加$a$,那么就令

\[\begin{cases} & s[l]+=a\\ & s[r+1]-=a \end{cases}\]

最后求出$s$序列的在每个位置上的前缀和即可。

注意判断边界条件,$r+1$有可能出界。

在区间特别大的时候,可以用一种$map$差分:

读入区间$[l,r]$,令:

\[\begin{cases} & m[l]+=x\\ & m[r+1]-=x \end{cases}\]

如果只关心区间重叠的次数的话,可以令$now=0$,用下面的遍历方法:

for(auto i=m.begin();i!=m.end();++i)
    now+=i->second

这样可以得出某个点被累加了几次,直到$now$被修改之前的所有点的重叠次数都等于$now$

二维差分

给定左上角$(x1,y1)$,右下角$(x2,y2)$,改变量为$x$,每次操作 :

\[\begin{cases} & C[x1][y1] += x\\ & C[x2 + 1][y2 + 1] += x\\ & C[x1][y2 + 1] -= x\\ & C[x2 + 1][y1] -= x \end{cases}\]

然后做一遍二维前缀和。

对于左上角$A (x1,y1)$,右下角$B (x2,y2)$

$dp[i][j]$表示$(1,1)$到$(i,j)$的所有数字的总和,那么有:

$dp[i][j]=dp[i-1][j]+dp[i][j-1]+C[i][j]-dp[i-1][j-1]$

同理A到B的矩形区域的和为:

$dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]$

树上差分

对a点到b点的路径进行修改:

\[\begin{cases} & 点权 \to v[a]++,v[b]++,v[lca(a,b)]-=2 \\ & 边权 \to v[a]++,v[b]++,v[lca(a,b)]--,v[fa(lca(a,b))]--(fa[x]是x的父节点) \end{cases}\]

累加的时候,从上到下正着跑一边$dfs$,初始值$ans=v$。

先处理儿子,再让$ans[fa]+=ans[son]$。

实际上改边权是改点权,某一条边的边权是它所连接的两个点当中深度更深的那个点的点权。