02.09_二维动态差分(区修单查)

二维动态差分(区修单查)

二维动态差分是二维差分的动态实现,通过二维树状数组维护差分数组,可以在 的时间复杂度内完成子矩阵修改和单点查询操作。

基本概念

二维动态差分的核心思想是:

  1. 使用二维树状数组维护差分数组
  2. 子矩阵修改转化为四个点的修改
  3. 单点查询通过二维前缀和实现
  4. 适用于子矩阵修改和单点查询交替的场景

实现方式

二维动态差分的关键操作:

  1. update:修改差分数组某个位置的值
  2. query:查询差分数组的二维前缀和
  3. rangeAdd:子矩阵增加操作
  4. pointQuery:单点查询

基本实现

class DynamicDifference2D {
private:
    vector<vector<int>> tree;
    int m, n;
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    void update(int x, int y, int val) {
        for (int i = x; i <= m; i += lowbit(i)) {
            for (int j = y; j <= n; j += lowbit(j)) {
                tree[i][j] += val;
            }
        }
    }
    
    int query(int x, int y) {
        int sum = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            for (int j = y; j > 0; j -= lowbit(j)) {
                sum += tree[i][j];
            }
        }
        return sum;
    }

public:
    DynamicDifference2D(int rows, int cols) : m(rows), n(cols) {
        tree.resize(m + 1, vector<int>(n + 1));
    }
    
    // 子矩阵[(x1,y1), (x2,y2)]增加val
    void rangeAdd(int x1, int y1, int x2, int y2, int val) {
        update(x1 + 1, y1 + 1, val);
        update(x1 + 1, y2 + 2, -val);
        update(x2 + 2, y1 + 1, -val);
        update(x2 + 2, y2 + 2, val);
    }
    
    // 查询位置(x,y)的值
    int pointQuery(int x, int y) {
        return query(x + 1, y + 1);
    }
};
class DynamicDifference2D {
    private int[][] tree;
    private int m, n;
    
    public DynamicDifference2D(int rows, int cols) {
        m = rows;
        n = cols;
        tree = new int[m + 1][n + 1];
    }
    
    private int lowbit(int x) {
        return x & (-x);
    }
    
    private void update(int x, int y, int val) {
        for (int i = x; i <= m; i += lowbit(i)) {
            for (int j = y; j <= n; j += lowbit(j)) {
                tree[i][j] += val;
            }
        }
    }
    
    private int query(int x, int y) {
        int sum = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            for (int j = y; j > 0; j -= lowbit(j)) {
                sum += tree[i][j];
            }
        }
        return sum;
    }
    
    // 子矩阵[(x1,y1), (x2,y2)]增加val
    public void rangeAdd(int x1, int y1, int x2, int y2, int val) {
        update(x1 + 1, y1 + 1, val);
        update(x1 + 1, y2 + 2, -val);
        update(x2 + 2, y1 + 1, -val);
        update(x2 + 2, y2 + 2, val);
    }
    
    // 查询位置(x,y)的值
    public int pointQuery(int x, int y) {
        return query(x + 1, y + 1);
    }
}
class DynamicDifference2D:
    def __init__(self, rows, cols):
        self.m = rows
        self.n = cols
        self.tree = [[0] * (cols + 1) for _ in range(rows + 1)]
    
    def lowbit(self, x):
        return x & (-x)
    
    def update(self, x, y, val):
        i = x
        while i <= self.m:
            j = y
            while j <= self.n:
                self.tree[i][j] += val
                j += self.lowbit(j)
            i += self.lowbit(i)
    
    def query(self, x, y):
        total = 0
        i = x
        while i > 0:
            j = y
            while j > 0:
                total += self.tree[i][j]
                j -= self.lowbit(j)
            i -= self.lowbit(i)
        return total
    
    # 子矩阵[(x1,y1), (x2,y2)]增加val
    def range_add(self, x1, y1, x2, y2, val):
        self.update(x1 + 1, y1 + 1, val)
        self.update(x1 + 1, y2 + 2, -val)
        self.update(x2 + 2, y1 + 1, -val)
        self.update(x2 + 2, y2 + 2, val)
    
    # 查询位置(x,y)的值
    def point_query(self, x, y):
        return self.query(x + 1, y + 1)

应用场景

二维动态差分在很多问题中都有应用:

  1. 动态图像处理
  2. 实时地图更新
  3. 在线矩阵修改
  4. 动态热力图
  5. 实时区域统计

示例:矩阵区域增加

class Solution {
private:
    DynamicDifference2D* dd;
    
public:
    vector<vector<int>> getModifiedMatrix(vector<vector<int>>& matrix, 
                                        vector<vector<int>>& operations) {
        int m = matrix.size(), n = matrix[0].size();
        dd = new DynamicDifference2D(m, n);
        
        // 执行所有更新操作
        for (const auto& op : operations) {
            int x1 = op[0], y1 = op[1];
            int x2 = op[2], y2 = op[3];
            int val = op[4];
            dd->rangeAdd(x1, y1, x2, y2, val);
        }
        
        // 查询每个位置的值
        vector<vector<int>> result(m, vector<int>(n));
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                result[i][j] = dd->pointQuery(i, j);
            }
        }
        
        return result;
    }
};
class Solution {
    private DynamicDifference2D dd;
    
    public int[][] getModifiedMatrix(int[][] matrix, int[][] operations) {
        int m = matrix.length, n = matrix[0].length;
        dd = new DynamicDifference2D(m, n);
        
        // 执行所有更新操作
        for (int[] op : operations) {
            int x1 = op[0], y1 = op[1];
            int x2 = op[2], y2 = op[3];
            int val = op[4];
            dd.rangeAdd(x1, y1, x2, y2, val);
        }
        
        // 查询每个位置的值
        int[][] result = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                result[i][j] = dd.pointQuery(i, j);
            }
        }
        
        return result;
    }
}
class Solution:
    def getModifiedMatrix(self, matrix: List[List[int]], operations: List[List[int]]) -> List[List[int]]:
        m, n = len(matrix), len(matrix[0])
        dd = DynamicDifference2D(m, n)
        
        # 执行所有更新操作
        for x1, y1, x2, y2, val in operations:
            dd.range_add(x1, y1, x2, y2, val)
        
        # 查询每个位置的值
        result = [[0] * n for _ in range(m)]
        for i in range(m):
            for j in range(n):
                result[i][j] = dd.point_query(i, j)
        
        return result

时间复杂度

  • 初始化:
  • 子矩阵修改:
  • 单点查询:
  • 空间复杂度:

动态差分 vs 静态差分

优点:

  1. 支持动态操作
  2. 单点查询更快
  3. 无需还原整个矩阵

缺点:

  1. 实现较复杂
  2. 常数较大
  3. 内存占用略多

注意事项

  1. 树状数组下标从1开始
  2. 子矩阵修改的边界处理
  3. 注意差分数组的范围
  4. 处理负数和溢出

练习建议

  1. 实现基本的二维动态差分
  2. 解决动态矩阵问题
  3. 比较静态和动态实现
  4. 尝试其他数据结构实现
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

03-14 18:48
重庆大学 C++
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务