输入数据a数组
a[i] | a0 | a1 | a2 | … \dots … | an |
---|---|---|---|---|---|
b[i] | b0 | b1 | b2 | … \dots … | bn |
b1=a1
b2=a2-a1
…
\dots
…
bn=an-an-1
以上各式累加相消得到
b1+b2+
…
\dots
…+bn=an
也就是说任一an可以由b数组累加求和得到并且任一个bi加上元素c等于在an上面+c。
对于区间[L,R]
,
aL=b1+b2+
…
\dots
…+bL
aL+1=b1+b2+
…
\dots
…+bL+bL+1
…
\dots
…
aR=b1+b2+
…
\dots
…+bR-1+bR
在bL=bL+c之后(也就是说bL增加c后)有
aL+c=b1+b2+
…
\dots
…+bL+c
aL+1+c=b1+b2+
…
\dots
…+(bL+c)+bL+1
…
\dots
…
aR+c=b1+b2+
…
\dots
…+(bL+c)+
…
\dots
…+bR-1+bR
令
a
L
′
=
a
L
+
c
a^{'}_{L}=a_L+c
aL′=aL+c,
a
L
+
1
′
=
a
L
+
1
+
c
a^{'}_{L+1}=a_{L+1}+c
aL+1′=aL+1+c
…
\dots
…
a
R
′
=
a
R
+
c
a^{'}_{R}=a_{R}+c
aR′=aR+c
(‘令’的操作可以把他看成一个整体)
替换上式
a
L
′
a^{'}_{L}
aL′=b1+b2+
…
\dots
…+bL+c
a
L
+
1
′
a^{'}_{L+1}
aL+1′=b1+b2+
…
\dots
…+(bL+c)+bL+1
…
\dots
…
a
R
′
a^{'}_{R}
aR′=b1+b2+
…
\dots
…+(bL+c)+
…
\dots
…+bR-1+bR
因此在b数组上面任一位置
i
i
i加一个c,会影响到[i,end]
的a数组,因为
∑
1
i
b
i
\sum^{i}_{1} b_i
∑1ibi累加得到
a
i
a_i
ai,b的[begin,end]
任一位置
i
i
i+c,会导致[i,end]
的a全部+c。
然后如果要实现只在[L,R]
内+c,那么需要在b[L]+=c
,b[R+1]-=c
,这样操作以后先是[L,R]
和[R+1,end]
全部元素+c,然后[R+1,end]
全部元素-c
然后[R+1,end]+c又-c就是没有变化,只有[L,R]
+c了。
最后把b数组用O(n)循环
(记住:an=b1+b2+
…
\dots
…+bn)
for(int i=1;i<=n;++i)
{
b[i]+=b[i-1];
cout<<b[i]<<" ";
}
就可以用b数组元素表示增加c后的a数组元素!
然后挨个输出b[i]就好啦!
#include<iostream>
#define N 100086
using namespace std;
int n,m,l,r,c,a[N],b[N];
void insert(int l,int r,int c){
b[l]+=c;
b[r+1]-=c;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) insert(i,i,a[i]);
//b[i]=a[i]-a[i-1];
for(int i=1;i<=m;++i) {
cin>>l>>r>>c;
insert(l,r,c);
}
for(int i=1;i<=n;++i)
{
b[i]+=b[i-1];
cout<<b[i]<<" ";
}
cout<<endl;
return 0;
}
代码中有insert(i,i,a[i]);
,我们如何理解呢?这里就只能死记硬背了,因为这代码
for(int i=1;i<=n;++i)
insert(i,i,a[i]);
和直接根据差分公式算出来的是完全一样的!这个确实是太巧妙了!
for(int i=1;i<=n;++i)
b[i]=a[i]-a[i-1];
是可以AC通过的
刚开始a和b全是0,
a
0
=
0
b
0
=
0
a_0=0 \\ b_0=0
a0=0b0=0
i | insert(i,i,a[i]) | b[i]=a[i]-a[i-1]; |
---|---|---|
i=1 | b 1 + = a 1 = > b 1 = b 1 + a 1 = 0 + a 1 = a 1 b 2 − = a 1 = > b 2 = b 2 − a 1 = 0 − a 1 = − a 1 b_1+=a_1=>b_1=b_1+a_1=0+a_1=a_1 \\ b_2-=a_1=>b_2=b_2-a_1=0-a_1=-a_1 b1+=a1=>b1=b1+a1=0+a1=a1b2−=a1=>b2=b2−a1=0−a1=−a1 | b 1 = a 1 − a 0 = a 1 b_1=a_1-a_0=a_1 b1=a1−a0=a1 |
i=2 | b 2 + = a 2 = > b 2 = b 2 + a 2 = − a 1 + a 2 = a 2 − a 1 b 3 − = a 2 = > b 3 = b 3 − a 2 = 0 − a 2 = − a 2 b_2+=a_2=>b_2=b_2+a_2=-a_1+a_2=a_2-a_1 \\ b_3-=a_2=>b_3=b_3-a_2=0-a_2=-a_2 b2+=a2=>b2=b2+a2=−a1+a2=a2−a1b3−=a2=>b3=b3−a2=0−a2=−a2 | b 2 = a 2 − a 1 b_2=a_2-a_1 b2=a2−a1 |
i=3 | b 3 + = a 3 = > b 3 = b 3 + a 3 = − a 2 + a 3 = a 3 − a 2 b_3+=a_3=>b_3=b_3+a_3=-a_2+a_3=a_3-a_2 b3+=a3=>b3=b3+a3=−a2+a3=a3−a2 | b 3 = a 3 − a 2 b_3=a_3-a_2 b3=a3−a2 |
… \dots … | … \dots … | … \dots … |
i=n | b n + = a n = > b n = b n + a n = − a n − 1 + a n = a n − a n − 1 b_n+=a_n=>b_n=b_n+a_n=-a_{n-1}+a_n=a_n-a_{n-1} bn+=an=>bn=bn+an=−an−1+an=an−an−1 | b n = a n − a n − 1 b_n=a_n-a_{n-1} bn=an−an−1 |
经过推导证明,发现这俩完全一样,可以互相替换!
后面又仔细想了一下,发现相似点了
对于上次循环
i
=
k
i=k
i=k,
有
b
k
=
b
k
+
a
k
b
k
+
1
=
b
k
+
1
−
a
k
=
−
a
k
i
=
k
+
1
b
k
+
1
=
b
k
+
1
+
a
k
+
1
=
a
k
+
1
−
a
k
b_k=b_k+a_k \\ b_{k+1}=b_{k+1}-a_k=-a_{k} \\ i=k+1\\ b_{k+1}=b_{k+1}+a_{k+1}=a_{k+1}-a_k
bk=bk+akbk+1=bk+1−ak=−aki=k+1bk+1=bk+1+ak+1=ak+1−ak
推导结果和b[i]=a[i]-a[i-1];
完全一样啊!这就是差分公式!