差分应用到解决题目中,主要是区间修改的问题。
如果让你给区间[l,r]中的每一个数都加上x,一般情况下会直接暴力循环将每一个数都加上x。
就像这样:
1 void update(int l,int r,int x) 2 { 3 for(int i=l;i<=r;i++) 4 { 5 a[i]+=x; 6 } 7 }
但是如果l-r非常大的话,这样做很明显时间复杂度很高,而差分则可以解决这个问题。
首先看一下前缀和的概念,前缀和是前 i 个数的和,就有了前缀和数组presum[maxn],前缀和数组中的每一个元素都存储了对应数组a[maxn]中前 i 个数的和,也就是presum[i]=presum[i-1]+a[i](前i-1个数的和加上当前数)。
差分可以说是和前缀和操作相反的,差分需要一个差分数组d[maxn],差分数组储存的是相邻元素的差,即d[i]=a[i] -a[i-1]。
举个例子:比如数组a={1,2,3,4,5,6},那么前缀和数组是presum={1,3,6,10,15,21},差分数组d={1,1,1,1,1}(少一个)。
构造差分数组的代码:(a数组是编号1-n的数组)
1 void makediff(int n) 2 { 3 for(int i=2;i<=n;i++) 4 { 5 d[i]=a[i]-a[i-1]; 6 } 7 }
进行区间修改操作,只需要在l和r这两个端点处对差分数组进行修改,假如在区间[l,r],中每个数都加上x。
那么将d[l]加上x,将d[r+1]减去x,因为是相邻的差,所以数a[r+1]-a[r]是差分数组d[r+1]的值,a[r+1]没变,而a[r]变了,所以..就这样。
看代码:
1 void update(int l,int r,int x) 2 { 3 d[l]+=x; 4 d[r+1]-=x; 5 return ; 6 }
要得到一个数a[i],需要推出这个数。
从第1个数依托差分数组得到每一个a[i],或者直接到要查询的数就停也可以。
代码如下:
1 int getnum(int pos) 2 { 3 for(int i=1;i<=n;i++) 4 { 5 a[i]=a[i-1]+d[i]; 6 } 7 return a[pos]; 8 }