📅  最后修改于: 2023-12-03 15:36:03.668000             🧑  作者: Mango
二维差分阵列可以用于快速计算矩阵区间的和,支持单点修改与区间查询操作。在一些图形学、计算几何以及动态规划问题中经常被使用。
二维差分阵列的实现原理基于前缀和的思想。假设有一个二维矩阵 matrix
,则在二维差分阵列中,我们要维护一个二维的数组 diff
,满足:
diff[i][j] = matrix[i][j] - matrix[i-1][j] - matrix[i][j-1] + matrix[i-1][j-1]
,其中 0 <= i < matrix.length
,0 <= j < matrix[0].length
。diff[0][0] = matrix[0][0]
。此时若想查询矩阵中以 x1
为左上角、以 x2
为右下角的矩阵区间之和,则可以使用如下公式:
sum(x1, y1, x2, y2) = diff[x2][y2] - diff[x1-1][y2] - diff[x2][y1-1] + diff[x1-1][y1-1]
。
根据容斥原理,可以把矩阵区间中重复计算的部分用差分数组的四个元素加减消掉。
为了方便单点修改操作,我们需要对差分数组进行类似前缀和的预处理操作。假设有一个操作 (x, y, val)
,表示将矩阵中 (x, y)
位置的元素加上 val
,则可以使用如下公式进行单点修改操作:
matrix[x][y] += val;
for (int i = x; i < matrix.length; i += i & -i) {
for (int j = y; j < matrix[0].length; j += j & -j) {
diff[i][j] += val - (i == x ? 0 : matrix[i-1][j]-matrix[i-1][j-1]) - (j == y ? 0 : matrix[i][j-1]-matrix[i-1][j-1]);
}
}
public class BinaryIndexedTree2D {
private int[][] matrix;
private int[][] diff;
public BinaryIndexedTree2D(int[][] matrix) {
this.matrix = matrix;
int n = matrix.length, m = matrix[0].length;
diff = new int[n+1][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
diff[i][j] = matrix[i-1][j-1] - (i > 1 ? matrix[i-2][j-1] : 0)
- (j > 1 ? matrix[i-1][j-2] : 0) + (i > 1 && j > 1 ? matrix[i-2][j-2] : 0);
for (int ii = i-(i&-i); ii < i; ii++) {
for (int jj = j-(j&-j); jj < j; jj++) {
diff[i][j] -= (ii > 0 && jj > 0 ? diff[ii][jj] : 0);
}
}
}
}
}
public void add(int x, int y, int val) {
matrix[x][y] += val;
for (int i = x+1; i < diff.length; i += i & -i) {
for (int j = y+1; j < diff[0].length; j += j & -j) {
diff[i][j] += val;
if (x > 0) diff[i][j] -= matrix[x-1][y];
if (y > 0) diff[i][j] -= matrix[x][y-1];
if (x > 0 && y > 0) diff[i][j] += matrix[x-1][y-1];
}
}
}
public int sum(int x1, int y1, int x2, int y2) {
return query(x2, y2) - query(x1-1, y2) - query(x2, y1-1) + query(x1-1, y1-1);
}
private int query(int x, int y) {
int res = 0;
for (int i = x+1; i > 0; i -= i & -i) {
for (int j = y+1; j > 0; j -= j & -j) {
res += diff[i][j];
}
}
return res;
}
}