差分与前缀和
绪论
差分与前缀是两个相反的过程,其中差分旨在以递推的形式记录数组元素,前缀和是以求和的方式灵活地面对区间询问
区间加常数
给定一个序列?(初值全为0)。有很多次操作,每个操作形如: l r k
意为将
?[?,?]
中的每个值加上?最后输出整个数组。 复杂度要求O(?).允许离线
这个有朴素的算法,就是老老实实一点点加,但是面对大量数据,就显得力不从心(复杂度O(n^2)
).
所以我们从差分的角度思考这个问题.不妨设数组左边界为L,右边界是R,且有L<=l<=r<=R
,
那么在区间加前后,除了a[l]
与a[r+1]
元素与前一位元素的差值改变了之外,剩下的均无变化,这样也就保证了能在O(1)
的时间内完成一个区间加的操作,我们不妨用数组p[]
来记录差值,也就是p[i]
表示a[i]-a[i-1]
综上所述
// 数组均初始化为0
int a[MAXN]; // 原数组,本质上是差分数组的前缀和
int p[MAXN]; // 差分数组
void add(int l,int r,int k){
// 区间加,复杂度O(1)
p[l]+=k;
p[r+1]-=k;
}
void get_a(){
// 生成a数组,复杂度O(n)
for(int i=1;i<=n;++i){
// 自1开始记数且保证a[0]为0
a[i]=a[i-1]+p[i];
}
}
区间加等差数列
给定一个序列?(初值全为0)。有很多次操作,操作有两种, 强制在线:
- 区间加等差数列
指定[?,?],指定等差数列?的首项和公差。 ?[?,?]每一个元素加上对应的元素:
?[?] += ?1,?[?+1] += ?2,⋯- 单点查询
指定?,求??.
e.g. 目前a={1,2,3,3,3,3},给[3,5]加上首项为2、公差为1的等差数列。
A变为: {1,2,5,6,7,3}
我们还是考虑其差分数组,对于p来说,其在(l,r]区间内的元素均加了一个常数d(公差),p[l]改为f1(首项)
,p[r+1]
也改变了,需要减去此等差数列的最后一项
我们根据前文区间加的经验可以得知,我们只需要再创建一个数组作为p的差分数组,就可以在O(1)时间内解决这个问题,我们将这个数组命名为r[]
然后我就发现我想多了,p[]目前需要满足单点修改和区间加和区间询问,需要用线段树才能解决
区间乱七八糟求和
给定序列?,有?次询问。每次询问指定[?,?].
要你回答:
a n s = ∑