差分数组就是 两项的差值组成的数组。
int a[10] = {1,2,3,4,5,6,7,8,9}; // 差分数组
int c[10] = {1,3,5,9,14,20,27,35,44}; //原数组
差分数组与原数组相当于是逆运算。
a数组的前缀和就是c数组
c数组 a[i] = c[i] - c[i-1]; 前缀和数组的差分就是a数组他们是可以自由转换的。
差分数组描述的是每项之间大小的关系,就是第i项比第i-1项大多少。
区间修改
如果要求修改一个区间[l, r] 中元素的值,如全部加上一个x
则让差分数组c[l] + x, c[r] - x; 这样就让l后面差分数组上升x 然后让r后面的差分数组下降x,这样就维护了[l ,r] 区间差分的关系, 然后差分数组的前缀和就反应了 a[i] 的大小, 这样如果需要大量跟新区间元素时,可以利用差分数组跟新,然后再最后需要使用a数组的时候,计算前缀合,然后就可以得到每个点元素的大小了
数组的每两项的差值描述了, 该数组相邻两两元素的大小关系, 即知道第一个元素就可以通过差分数组计算出整个数组, 也就是前缀和。
a[i] = a[i-1] + c[i] // a[i] 比 a[i-1] 大 c[i]
c[i] = a[i] - a[i-1] // 差分数组与前缀和数组逆运算
[P3406 海底高铁]
差分练习题
#include<string>
#include<iostream>
#define ll long long
using namespace std;
const int maxn = 100010;
ll a[maxn];
ll c[maxn];
int n, k;
ll p[maxn][3];
long long ans = 0;
long long temp = 0;
inline void add(int x, int y) { //区间修改
c[x]++;
c[y+1]--;
}
int main() {
scanf("%d%d", &n, &k);
int pre;
scanf("%d", &pre);
for(int i = 1; i < k; i++) {
int t;
scanf("%d", &t);
if(pre < t) add(pre, t - 1);
else add(t, pre - 1);
pre = t;
//scanf("%d", &order[i]);
}
for(int i = 1; i <= n-1; i++) {
scanf("%d%d%d", &p[i][0], &p[i][1], &p[i][2]);
}
for(int i = 1; i <= n; i++) {
c[i] += c[i-1]; //计算前缀和,差分数组转化为前缀和数组,前缀和数组的每个点就是区间中的点值
// printf("%d ", c[i]);
}
for(int i = 1; i < n; i++) { //计算每条地铁的花费
ll card, notCard;
notCard = c[i] * p[i][0];
card = (c[i]) * p[i][1] + p[i][2];
ans += min(notCard, card);
}
printf("%lld", ans);
return 0;
}