区间增减操作——差分数组

在这里插入图片描述
(^ _ ^)
这个题
差分数组是一种用于高效处理区间更新操作的数据结构。它在处理数组中的区间增减操作时非常有用,能够将区间更新的时间复杂度从 O(n) 降低到 O(1)。


差分数组的定义

给定一个数组 a,其差分数组 diff 定义为:

  • diff[0] = a[0](第一个元素保持不变);
  • 对于 i > 0diff[i] = a[i] - a[i-1](当前元素与前一个元素的差值)。

差分数组的性质

  1. 差分数组的前缀和可以还原原始数组。
  2. 对差分数组进行区间更新操作,可以高效地反映到原始数组中。

差分数组的作用

差分数组的核心作用是高效处理区间更新。例如:

  • 如果需要对数组 a 的区间 [L, R] 中的每个元素增加一个值 val,可以通过对差分数组 diff 进行以下操作:
    • diff[L] += val
    • diff[R+1] -= val(如果 R+1 在数组范围内)。

通过这种方式,区间更新的时间复杂度从 O(n) 降低到 O(1)。


差分数组的示例

示例 1:构造差分数组

假设原始数组为:

a = [2, 5, 3, 1, 4]

其差分数组 diff 为:

diff[0] = a[0] = 2
diff[1] = a[1] - a[0] = 5 - 2 = 3
diff[2] = a[2] - a[1] = 3 - 5 = -2
diff[3] = a[3] - a[2] = 1 - 3 = -2
diff[4] = a[4] - a[3] = 4 - 1 = 3

所以差分数组为:

diff = [2, 3, -2, -2, 3]
示例 2:通过差分数组还原原始数组

对差分数组 diff 求前缀和,可以还原原始数组 a

a[0] = diff[0] = 2
a[1] = diff[0] + diff[1] = 2 + 3 = 5
a[2] = diff[0] + diff[1] + diff[2] = 2 + 3 + (-2) = 3
a[3] = diff[0] + diff[1] + diff[2] + diff[3] = 2 + 3 + (-2) + (-2) = 1
a[4] = diff[0] + diff[1] + diff[2] + diff[3] + diff[4] = 2 + 3 + (-2) + (-2) + 3 = 4

还原后的原始数组为:

a = [2, 5, 3, 1, 4]
示例 3:区间更新

假设我们需要对原始数组 a 的区间 [1, 3] 中的每个元素增加 2,可以通过差分数组实现:

  1. 对差分数组 diff 进行以下操作:
    • diff[1] += 2
    • diff[4] -= 2(因为 R+1 = 4)。
  2. 更新后的差分数组为:
    diff = [2, 5, -2, -2, 1]
    
  3. 通过差分数组还原原始数组:
    a[0] = 2
    a[1] = 2 + 5 = 7
    a[2] = 2 + 5 + (-2) = 5
    a[3] = 2 + 5 + (-2) + (-2) = 3
    a[4] = 2 + 5 + (-2) + (-2) + 1 = 4
    
    更新后的原始数组为:
    a = [2, 7, 5, 3, 4]
    

差分数组的应用场景

  1. 区间增减操作

    • 对数组的某个区间进行统一的增减操作。
    • 例如:对数组 a 的区间 [L, R] 中的每个元素增加 val
  2. 高效计算区间和

    • 结合前缀和,可以高效计算区间和。
  3. 动态数组更新

    • 在需要频繁更新数组区间值的场景中,差分数组可以显著提高效率。

代码实现

以下是差分数组的 cpp实现:

#include <iostream>  
#include <vector>  

using namespace std;  


vector<int> build_diff_array(const vector<int>& a) {  
    int n = a.size();  
    vector<int> diff(n);  
    diff[0] = a[0];  
    for (int i = 1; i < n; ++i) {  
        diff[i] = a[i] - a[i - 1];  
    }  
    return diff;  
}  


void update_diff_array(vector<int>& diff, int L, int R, int val) {  
    diff[L] += val;  
    if (R + 1 < diff.size()) {  
        diff[R + 1] -= val;  
    }  
}  


vector<int> restore_array(const vector<int>& diff) {  
    vector<int> a;  
    a.push_back(diff[0]);  
    for (int i = 1; i < diff.size(); ++i) {  
        a.push_back(a[i - 1] + diff[i]);  
    }  
    return a;  
}  

int main() {  
    vector<int> a = {2, 5, 3, 1, 4};  

    vector<int> diff = build_diff_array(a);  
    cout << "Difference array: ";  
    for (int num : diff) {  
        cout << num << " ";  
    }  
    cout << endl; // Output: [2, 3, -2, -2, 3]  
 
    update_diff_array(diff, 1, 3, 2);  
    cout << "Updated difference array: ";  
    for (int num : diff) {  
        cout << num << " ";  
    }  
    cout << endl; // Output: [2, 5, -2, -2, 1]  


    vector<int> a_updated = restore_array(diff);  
    cout << "Updated original array: ";  
    for (int num : a_updated) {  
        cout << num << " ";  
    }  
    cout << endl; // Output: [2, 7, 5, 3, 4]  

    return 0;  
}

总结

差分数组是一种非常实用的工具,特别适合处理区间更新问题。它的核心思想是通过记录相邻元素的差值,将区间更新操作转化为单点更新操作,从而大幅提高效率。

AC代码

#include <iostream>
using namespace std;

const int MAXN = 1005;
int diff[MAXN][MAXN];  // 定义二维差分数组

int main() {
    int n, m;
    cin >> n >> m;

    // 处理每一块地毯
    for (int i = 0; i < m; ++i) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        // 在差分数组上进行标记
        diff[x1][y1]++;
        diff[x2 + 1][y1]--;
        diff[x1][y2 + 1]--;
        diff[x2 + 1][y2 + 1]++;
    }

    // 还原原数组
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            // 通过前缀和运算还原
            diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
            cout << diff[i][j];
            if (j < n) {
                cout << " ";
            }
        }
        cout << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值