算法笔记--差分数组

差分数组是什么呢?

差分数组是前缀和的逆运算。

一般定义的差分数组是原数组相邻两个元素之间的差的数组,后面也有非一般的定义。

如一维原数组是a[i],则一阶差分数组是d[i] = a[i]-a[i-1],对一阶差分数组d[]求一遍前缀和就能得到原数组a[];

一阶差分数组的一阶差分数组是二阶差分数组,对二阶差分数组需要求两遍前缀和才能得到原数组;

以此类推,n阶差分数组是n-1阶差分数组的一阶差分数组,需要求n遍前缀和才能得到原数组。

若没有特殊说明,以下描述中差分数组表示一阶差分数组。

问题1:连续区域加上相同值,对原数组连续区域加上相同值相当于对差分数组有限个位置进行操作,一般

用树状数组维护这个差分数组。

一维:

在原数组a[]中,对[l, r]区间的每一个元素加x,相当于在差分数组进行如下操作:

d[l] += x;

d[r+1] -= x;

这里用到了容斥原理,d[l]加x在求前缀和时给[l, ∞]加上x,d[r+1]减x在求前缀和时给[r+1, ∞]减上x,两个影响合并就是对[l, r]加上x。

二维:

在二维原数组a[][]中,对[(x1,y1), (x2,y2)]矩形区域内的每一个元素加x,相当于在差分数组中进行如下操作:

d[x1][y1] += x;

d[x1][y2+1] -= x;

d[x2+1][y1] -= x;

d[x2+1][y2+1] += x;

三维:

在三维原数组a[][][]中,对[(x1,y1,z1), (x2,y2,z2)]长方体区域内的每一个元素加x,相当于在差分数组中进行如下操作:

d[x1][y1][z1] += x;

d[x2+1][y1][z1] -= x;

d[x1][y2+1][z1] -= x;

d[x1][y1][z2+1] -= x;

d[x1][y2+1][z2+1] += x;

d[x2+1][y1][z2+1] += x;

d[x2+1][y2+1][z1] += x;

d[x2+1][y2+1][z2+1] -= x;

通过找规律,我们发现,(x2,y2,z2...)的出现次数是奇数则进行减法,偶数则进行加法。

例题a:http://codeforces.com/problemset/problem/816/B

例题b:http://codeforces.com/problemset/problem/834/B

例题c:http://acm.hdu.edu.cn/showproblem.php?pid=1556

问题2:对原数组a[]连续区间[l, r]加上等差数列,以(1 2 3 4 5 ...)进行举例,相当于在二阶差分数组d2[]上进行如下操作:

d2[l]++; d2[r+1] -= r-l+2; d2[r+2] += r-l+1;

对d2[]求一遍前缀和得到原数组的一阶差分数组d[]的改变:

d[l, r] += 1, d[r+1] -= r-l+1, d[r+2,∞] += 0

再对这个一阶差分d[]求一遍前缀和,得到原数组a[]的改变:

a[l] += 1, a[l+1] += 2, ... , a[r] += r-l+1, a[r+1, ∞] += 0

例题:http://arc077.contest.atcoder.jp/tasks/arc077_c

问题3:对原数组a[]连续区间[l, r]加上斐波那契数列(1 1 2 3 5 8 13 ...),斐波那契数列通项公式为fib[i] = fib[i-1] + fib[i-2],初始值fib[0] = fib[1] = 1。

解决这个问题需要对普通的一阶差分数组的定义进行修改,修改成d[i] = a[i] - a[i-1] - a[i-2],将其命名为斐波那契差分数组;

同时,求前缀和操作也不能是普通的前缀和a[i] = a[i] + a[i-1],而是修改成a[i] = a[i] + a[i-1] + a[i-2],将其命名为斐波那契前缀和。

注意,对斐波那契差分数组求斐波那契前缀和才能得到原数组。

那么对连续区间加上斐波那契数列,相当于在斐波那契差分数组上进行如下操作:

d[l] ++;

d[r+1] -= fib[r-l+1];

d[r+2] -= fib[r-l];

例题:https://codeforces.com/contest/1634/problem/F

posted @ 2017-10-29 18:13  Wisdom+.+  阅读(875)  评论(0编辑  收藏  举报