前缀和和差分模板

说明

不论是一维还是二维
前缀和的作用都是快速求解某个区间的数据和
差分的作用都是快速进行区间数值的修改

[注]:上方将某个区间标记为了重点,在做题时一旦遇到区间内数量等字眼,应当及时反应到前缀和

一维前缀和

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n, m;
int a[N];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i)
    {
        cin >> a[i];
        a[i] += a[i - 1]; // 原数组直接作为前缀和数组
    }
    while (m --)
    {
        int l, r;
        cin >> l >> r;
        cout << a[r] - a[l - 1] << endl;
    }
    return 0;
}

一维差分

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n, m;
int b[N];

void insert(int l, int r, int v)
{
    b[l] += v;
    b[r + 1] -= v;
}
int main()
{
    cin >> n >> m;
    // 构造差分数组
    for (int i = 1; i <= n; ++ i)
    {
        int v;
        cin >> v;
        insert(i, i, v); // 把原数组全部看为0, 读入操作可以等效为修改操作。区别于传统的差分数组构造方法,和后续操作相统一
    }
    // 进行修改
    while (m --)
    {
        int l, r, v;
        cin >> l >> r >> v;
        insert(l, r, v);
    }
    // 求差分的前缀和即得原始数组
    for (int i = 1; i <= n; ++ i)
    {
        b[i] += b[i - 1];
        cout << b[i] << ' ';
    }
    cout << endl;
    return 0;
}

二维前缀和

#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int s[N][N];

int main()
{
    cin >> n >> m >> q;
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 1; j <= m; ++ j)
        {
            cin >> s[i][j];
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; // 二维前缀和数组构造
        }
    }
    while (q --)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
    }
    return 0;
}

二维差分

/**
 * 二维差分的真实含义已经不再和一维一样清晰了,为了更好理解,把它看为一个便于修改矩阵数值的工具更好一些
 * 最难理解的位置在于insert函数进行的那4个操作,想要理解这个,需要联系差分的前缀和的求法,前缀和就是求左上角
 * 所有方格的数值和,也就是说当b[i, j]发生改变后,右下角所有前缀和包含b[i, j]的元素的值都会发生对应的改变
 * 比如b[i, j]+2,效果就是让原数组中在[i, j]右下角的所有元素值都+2,前缀和对应的就是原数组的值,而差分数组的改变对应的就是前缀和的改变也就对应着原始数组的改变
 * 理解了b[i, j]的改变会影响它右下角所有元素的值,结合insert的目的就不难理解那4句话了
 */
#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int b[N][N];

void insert(int x1, int y1, int x2, int y2, int v) // 作用:将左上角为[x1, y1],右下角为[x2, y2]的矩阵中的数值都+v
{
    b[x1][y1] += v;
    b[x2 + 1][y1] -= v;
    b[x1][y2 + 1] -= v;
    b[x2 + 1][y2 + 1] += v;
}
int main()
{
    cin >> n >> m >> q;
    // 构造二维差分数组,和一维差分一样,构造方法有别于传统构造方法
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= m; ++ j)
        {
            int v;
            cin >> v;
            insert(i, j, i, j, v);
        }
    // 进行修改操作
    while (q --)
    {
        int x1, y1, x2, y2, v;
        cin >> x1 >> y1 >> x2 >> y2 >> v;
        insert(x1, y1, x2, y2, v);
    }
    // 求差分的前缀和数组即得原始数组
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 1; j <= m; ++ j)
        {
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
            cout << b[i][j] << ' ';
        }
        cout << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/G-H-Y/p/14287618.html