IndexTree特点:
1)支持区间查询
2)没有线段树那么强,但是非常容易改成一维、二维、三维的结构
3)只支持单点更新

IndexTree实现

对于前缀和数组,当原数组不变时,可以快速获取某个范围累加和,但是当原数组一个范围的数发生改变时,前缀和数组受影响,需要重新计算,时间复杂度高。

IndexTree 下标从1开始
tree[1]管理原数组下标1;tree[2]管理原数组下标1、2;tree[3]管理原数组3;tree[4]管理原数组1、2、3、4
27 IndexTree - 图1

每个下标负责:该下标的二进制 左右边的1去掉+1~该下边范围的数
如下标4,对应二进制 0100 ——》最右边1去掉+1 = 0001~0100范围的数

  1. public static class IndexTree {
  2. private final int[] tree;
  3. private final int num;
  4. public IndexTree(int size) {
  5. num = size;
  6. tree = new int[num + 1];
  7. }
  8. // 当前位置 加上 去掉最右边1的位置
  9. public int sum(int index) {
  10. int res = 0;
  11. while (index > 0) {
  12. res += tree[index];
  13. index -= index & -index;
  14. }
  15. return res;
  16. }
  17. // 受影响的位置 当前位置,和 加上最右边的1 的位置
  18. public void add(int index, int d) {
  19. while (index <= num) {
  20. tree[index] += d;
  21. index += index & -index;
  22. }
  23. }
  24. }
  25. public static class Right {
  26. private final int[] nums;
  27. public Right(int size) {
  28. int n = size + 1;
  29. nums = new int[n + 1];
  30. }
  31. public int sum(int index) {
  32. int ret = 0;
  33. for (int i = 1; i <= index; i++) {
  34. ret += nums[i];
  35. }
  36. return ret;
  37. }
  38. public void add(int index, int d) {
  39. nums[index] += d;
  40. }
  41. }

IndexTree可方便用于二维数组

每一维做 运算

public static class IndexTree2D {
    private int[][] tree;
    private int[][] nums;
    private int r;
    private int c;

    public IndexTree2D(int[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return;
        }
        r = matrix.length;
        c = matrix[0].length;
        tree = new int[r + 1][c + 1];
        nums = new int[r][c];
        for (int i = 0; i < matrix.length; i++) {
            System.arraycopy(matrix[i], 0, nums[i], 0, c);
            System.arraycopy(matrix[i], 0, tree[i + 1], 1, c);
        }
    }

    public int sum(int row, int col) {
        int res = 0;
        for (int i = row + 1; i > 0; i -= (i & -i)) {
            for (int j = col + 1; j > 0; j -= (j & -j)) {
                res += tree[i][j];
            }
        }
        return res;
    }

    public void update(int row, int col, int d) {
        if (r == 0 || c == 0) {
            return;
        }

        int add = d - nums[row][col];
        nums[row][col] = d;
        for (int i = row + 1; i <= r; i += (i & -i)) {
            for (int j = col + 1; j <= c; j += (j & -j)) {
                tree[i][j] += add;
            }
        }
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
        if (r == 0 || c == 0) {
            return 0;
        }
        return sum(row2, col2) + sum(row1 - 1, col1 - 1) - sum(row1 - 1, col2) - sum(row2, col1 - 1);
    }
}