差分数组:
对于 原数组a:a[1]、a[2]、a[3]、… 、a[n],将其转化为差分数组:
{
f
[
1
]
=
a
[
1
]
f
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
,
i
⩾
2
\left\{\begin{matrix} & f[1]=a[1]\\\\ & f[i]=a[i]-a[i-1],i\geqslant 2 \end{matrix}\right.
⎩⎨⎧f[1]=a[1]f[i]=a[i]−a[i−1],i⩾2
那么 差分数组f:a[1]、a[2] - a[1]、a[3] - a[2]、… 、a[n] - a[n-1]
差分数组主要是可以 以O(1)的时间复杂度修改区间,但是 单点查询操作的时间复杂度变为了O(n)
不过维护一个存储差分数组区间求和的线段树,可以将单点查询操作的时间复杂度降为O(logn)(即线段树的区间查询),不过同时修改区间的时间复杂度也会升为O(logn)(即线段树的单点更新),算是一个折中的修改了。
①差分数组的建立
int n,a[maxn],f[maxn];
f[1]=a[1]; //注意首项
for(int i=2;i<=n;i++)
f[i]=a[i]-a[i-1];
②差分数组的区间修改
令[L, R] 区间内的 a[i] 全部 + x,对于差分数组,可以发现,只需要 令 f[L] + x ,f[R+1] - x 即可。
void updata(int L,int R,int x)
{
f[L]+=x;
if(R+1<=n) //注意限制
f[R+1]-=x;
}
③差分数组的单点查询
查询 a[x] 的值,对于差分数组:
a
[
x
]
=
∑
i
=
1
x
f
[
i
]
a[x]=\sum_{i=1}^{x}f[i]
a[x]=i=1∑xf[i]
int query(int x)
{
int sum=0;
for(int i=1;i<=x;i++)
sum+=f[i]; //从f[1]加到f[x]
return sum;
}
差分数组的运用比较灵活,例如 Color the ball HDU - 1556 中,共 1 ~ N 个气球,每次给某个区间内的气球涂一次色,问最后各个气球各涂了多少次颜色,就可以很好地用差分数组来解决。
此外,在求带有区间修改的区间gcd时,差分数组也有妙用。