前缀和+差分

https://blog.csdn.net/k_r_forever/article/details/81775899
已知一个数组a[i],对其进行以下操作:
(1)区间修改。
(2)在所有区间修改都结束后,区间查询。
设数组大小为n,询问次数为m,则线段树或树状数组的时间复杂度为O(mlogn),前缀和+差分的时间复杂度是O(n+m)
前缀和:s[n]=a[1]+a[2]+...+a[n]
差分:d[n]=a[n]-a[n-1]
先设所有差分为0,区间修改只修改l和r+1的差分,修改完成后先计算差分的累积和add=add+d[i],再由s[i]+=s[i-1]+add算出a[i]的前缀和,查询的时候用s[l,r]=s[r]-s[l-1]。(这种算法也可以单点修改和单点查询)

#include<iostream>
using namespace std;
const int maxn = 500010;
int n, m;
int s[maxn], d[maxn];
int temp ,x, y, k, add;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
    }
    cin >> m;
    for (int i = 1; i <= m; i++) {
        cin >> x >> y >> k;
        d[x] += k;
        d[y + 1] -= k;
    }
    for (int i = 1; i <= n; i++) {
        add += d[i];
        s[i] += s[i - 1] + add;
    }
    cin >> m;
    for (int i = 1; i <= m; i++) {
        cin >> x >> y;
        cout << s[y] - s[x - 1] << endl;
    }
    return 0;
}

二维前缀和:
已知一个二维数组(矩阵)a[N][M],给出t个询问:x1,y1,x2,y2,求以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的元素和(包含左上角和右下角的元素)。
这题也可以用线段树做,不过要用二维线段树,很麻烦。
想到容斥原理,设从(1,1)(i,j)的子矩阵元素和为s[i][j],有:
s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j]
查询的时候,又有:
res=s[x_2][y_2]-s[x_2][y_1-1]-s[x_1-1][y_2]+s[x_1-1][y_1-1]

#include<iostream>
using namespace std;
int m, n;
int s[1001][1001];
int sx, sy, ex, ey;
int main() {
    cin >> m >> n;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> s[i][j];
        }
    }
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    }
    while (1) {
        cin >> sx >> sy >> ex >> ey;
        cout << s[ex][ey] - s[sx - 1][ey] - s[ex][sy - 1] + s[sx - 1][sy - 1] << endl;
    }
    return 0;
}

二维前缀和也可以用差分,要修改四个位置:

d[x1][y1]+=p;d[x2+1][y2+1]+=p;
d[x2+1][y1]-=p;d[x1][y2+1]-=p;
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容