前缀和与差分

前缀和向后,差分向前。

下标都是从1开始

前缀和

一维前缀和:

构造:
S[i] = S[i - 1] + A[i]
求A数组中[l, r]的和:
S[r] - S[l - 1]

二维前缀和:

构造:

for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= m; j ++) {
        cin >> A[i][j];
        S[i][j] = S[i - 1][j] + S[i][j - 1] + A[i][j] - S[i - 1][j - 1];
    }
}

求A数组中[x1, y1]到[x2, y2]之间的和:
S[x2][y2] - S[x1 - 1][y2] - S[x2][y1 - 1] + S[x1 - 1][y1 - 1]

差分

一维差分:

构造:

//insert:给A数组中[l, r]中全部数都加上c
void insert(int l, int r, int c) {
    B[l] += c;
    B[r + 1] -= c;
}
for(int i = 1; i <= n; i ++) {
    cin >> A[i];
    insert(i, i, A[i]);  //构造A数组的差分数组B
}

最后对差分B数组求前缀和即可得到操作后的A数组:

for(int i = 1; i <= n; i ++) {
    A[i] = A[i - 1] + B[i];
}

二维差分:

构造:

void insert(int x1, int y1, int x2, int y2, int c) {
    B[x1][y1] += c;
    B[x2 + 1][y1] -= c;
    B[x1][y2 + 1] -= c;
    B[x2 + 1][y2 + 1] += c;
}
for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= m; j ++) {
        cin >> A[i][j];
        insert(i, j, i, j, A[i][j]);
    }
}

求A数组:

for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= m; j ++) {
        A[i][j] = A[i - 1][j] + A[i][j - 1] + B[i][j] - A[i - 1][j - 1];
    }
}

为什么B数组通过insert操作就影响到了A数组呢?
一维:若在B[l]加上c,那么会影响A数组中A[l~last]都会加上c,再从B[r + 1]减去c,那么就能在A数组中[l, r]区域全部加上c,即所谓差分数组是向后影响的。
二维同理。

posted @ 2022-10-10 10:33  wushucan  阅读(29)  评论(0)    收藏  举报