差分(1)

差分是什么

我也不知道啊!

简单地说,差分数组就是↓这样的。

d[i] = a[i] -a[i - 1];

(d 是差分数组 ,a 是原数组)

(a[0]=0)

(两个数组下标从1开始)

举个栗子:

a[] = { 1,2,3,6,9,13 }

d[] = { 1,1,1,3,3,4  }

 

差分有什么用

我还是不知道啊!

最简单的,差分数组可以运用于区间修改&单点查询。

来道题目

N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便会骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?

简化一下题意:N次操作,将区间 [a,b] ++,N此操作后,输出每个点的值。(初始值为零)

这题就是上述的最简单的应用。

先看下代码

#include<cstdio>
const int N=1e5;
int c[N+10],s[N+10];
int main(){
    int n;
    int a,b;
    for(int i=1;i<=n;i++){
                scanf("%d%d,&a,&b);
        c[a]++;
        c[b+1]--;
    }
    for(int i=1;i<=n;i++){
        s[i]=c[i]+s[i-1];
    }
    for(int i=1;i<=n;i++){
        printf("%d ",s[i]);
    }
        return 0;
}      

是不是很简单

 

现在来分析一下

现有两个命题,需证明

1.差分数组的前缀和为原数组

2.区间修改只影响差分数组中的两个点——左端点 和 右端点的下一位

留作习题答案略,读者自证不难

 

前缀和

关于前缀和也有很多应用,此处不再赘述。

简单介绍一下概念:

s[i]=a[1]+a[2]+...+a[i]

也就是 s[i]=s[i-1]+a[i].

 

证明:(虽说很简单,但也写一下吧。)

s[i]=d[1]+d[2]+d[3]+...+d[i]

  =a[1]-a[0]+a[2]-a[1]+a[3]-a[2]+...+d[i]-d[i-1];

     =d[i]-a[0]

   =d[i]

这样,就得到了差分数组的前缀和等于原数组

修改前 a[1] a[2] a[3] a[4] a[5] a[6] a[7]
c[1] c[2] c[3] c[4] c[5] c[6] c[7]
修改后 a[1] a[2] a[3]+k a[4]+k a[5]+k a[6] a[7]
c[1] c[2] c[3]+k c[4] c[5]-k c[6] c[7]
下标 1 2 3(left) 4 5 (right) 6 7

列个表,惊喜的发现,只有 left 和right +1 两个点的值有改变

为什么呢?

这回真不写了,实在太过简单了,自己观察或者写写吧,相信不过几分钟的事。

 

这样子,就把对整段区间的修改,转换为了对两个节点的修改。

大大减小了时间复杂度。

在回顾一下上面的题目与代码,是不是这样的呢?

 

其他:比如树上差分,差分约束,就等下次见吧

(第一篇,望多多海涵)

 

posted @ 2022-02-06 23:03  ~dream~  阅读(31)  评论(0编辑  收藏  举报