Skip to content

307. Range Sum Query - Mutable 👍

Approach 1: Fenwick Tree

  • Time: Constructor: $O(n)$, update(index: int, val: int): $O(\log n)$, sumRange(left: int, right: int): $O(\log n)$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class FenwickTree {
 public:
  FenwickTree(int n) : sums(n + 1) {}

  void update(int i, int delta) {
    while (i < sums.size()) {
      sums[i] += delta;
      i += lowbit(i);
    }
  }

  int get(int i) const {
    int sum = 0;
    while (i > 0) {
      sum += sums[i];
      i -= lowbit(i);
    }
    return sum;
  }

 private:
  vector<int> sums;

  static inline int lowbit(int i) {
    return i & -i;
  }
};

class NumArray {
 public:
  NumArray(vector<int>& nums) : nums(nums), tree(nums.size()) {
    for (int i = 0; i < nums.size(); ++i)
      tree.update(i + 1, nums[i]);
  }

  void update(int index, int val) {
    tree.update(index + 1, val - nums[index]);
    nums[index] = val;
  }

  int sumRange(int left, int right) {
    return tree.get(right + 1) - tree.get(left);
  }

 private:
  vector<int> nums;
  FenwickTree tree;
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class FenwickTree {
  public FenwickTree(int n) {
    sums = new int[n + 1];
  }

  public void update(int i, int delta) {
    while (i < sums.length) {
      sums[i] += delta;
      i += lowbit(i);
    }
  }

  public int get(int i) {
    int sum = 0;
    while (i > 0) {
      sum += sums[i];
      i -= lowbit(i);
    }
    return sum;
  }

  private int[] sums;

  private static int lowbit(int i) {
    return i & -i;
  }
}

class NumArray {
  public NumArray(int[] nums) {
    this.nums = nums;
    tree = new FenwickTree(nums.length);
    for (int i = 0; i < nums.length; ++i)
      tree.update(i + 1, nums[i]);
  }

  public void update(int index, int val) {
    tree.update(index + 1, val - nums[index]);
    nums[index] = val;
  }

  public int sumRange(int left, int right) {
    return tree.get(right + 1) - tree.get(left);
  }

  private int[] nums;
  private FenwickTree tree;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class FenwickTree:
  def __init__(self, n: int):
    self.sums = [0] * (n + 1)

  def update(self, i: int, delta: int) -> None:
    while i < len(self.sums):
      self.sums[i] += delta
      i += FenwickTree.lowbit(i)

  def get(self, i: int) -> int:
    summ = 0
    while i > 0:
      summ += self.sums[i]
      i -= FenwickTree.lowbit(i)
    return summ

  @staticmethod
  def lowbit(i: int) -> int:
    return i & -i


class NumArray:
  def __init__(self, nums: List[int]):
    self.nums = nums
    self.tree = FenwickTree(len(nums))
    for i, num in enumerate(nums):
      self.tree.update(i + 1, num)

  def update(self, index: int, val: int) -> None:
    self.tree.update(index + 1, val - self.nums[index])
    self.nums[index] = val

  def sumRange(self, left: int, right: int) -> int:
    return self.tree.get(right + 1) - self.tree.get(left)

Approach 2: Segment Tree w/ SegmentTreeNode

  • Time: Constructor: $O(n)$, update(index: int, val: int): $O(\log n)$, sumRange(left: int, right: int): $O(\log n)$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
struct SegmentTreeNode {
  int lo;
  int hi;
  int sum;
  SegmentTreeNode* left;
  SegmentTreeNode* right;
  SegmentTreeNode(int lo, int hi, int sum, SegmentTreeNode* left = nullptr,
                  SegmentTreeNode* right = nullptr)
      : lo(lo), hi(hi), sum(sum), left(left), right(right) {}
  ~SegmentTreeNode() {
    delete left;
    delete right;
    left = nullptr;
    right = nullptr;
  }
};

class SegmentTree {
 public:
  explicit SegmentTree(const vector<int>& nums)
      : root(build(nums, 0, nums.size() - 1)) {}

  void update(int i, int val) {
    update(root.get(), i, val);
  }

  int query(int i, int j) const {
    return query(root.get(), i, j);
  }

 private:
  std::unique_ptr<SegmentTreeNode> root;

  SegmentTreeNode* build(const vector<int>& nums, int lo, int hi) const {
    if (lo == hi)
      return new SegmentTreeNode(lo, hi, nums[lo]);
    const int mid = (lo + hi) / 2;
    SegmentTreeNode* left = build(nums, lo, mid);
    SegmentTreeNode* right = build(nums, mid + 1, hi);
    return new SegmentTreeNode(lo, hi, left->sum + right->sum, left, right);
  }

  void update(SegmentTreeNode* root, int i, int val) {
    if (root->lo == i && root->hi == i) {
      root->sum = val;
      return;
    }
    const int mid = (root->lo + root->hi) / 2;
    if (i <= mid)
      update(root->left, i, val);
    else
      update(root->right, i, val);
    root->sum = root->left->sum + root->right->sum;
  }

  int query(SegmentTreeNode* root, int i, int j) const {
    // [lo, hi] lies completely inside [i, j].
    if (i <= root->lo && root->hi <= j)
      return root->sum;
    // [lo, hi] lies completely outside [i, j].
    if (j < root->lo || root->hi < i)
      return 0;
    return query(root->left, i, j) + query(root->right, i, j);
  }
};

class NumArray {
 public:
  NumArray(vector<int>& nums) : tree(nums) {}

  void update(int index, int val) {
    tree.update(index, val);
  }

  int sumRange(int left, int right) {
    return tree.query(left, right);
  }

 private:
  SegmentTree tree;
};

Approach 3: Segment Tree w/ tree array

  • Time: Constructor: $O(n)$, update(index: int, val: int): $O(\log n)$, sumRange(left: int, right: int): $O(\log n)$
  • Space: $O(n)$
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
template <typename T>
class RangeQuery {
 public:
  virtual void update(int index, int val);
  virtual T query(int i, int j);

 private:
  virtual T merge(T a, T b);

 protected:
  int left(int treeIndex) {
    return 2 * treeIndex + 1;
  }

  int right(int treeIndex) {
    return 2 * treeIndex + 2;
  }
};

class SegmentTree : RangeQuery<int> {
 public:
  explicit SegmentTree(const vector<int>& nums)
      : n(nums.size()), tree(nums.size() * 4) {
    build(nums, 0, 0, n - 1);
  }

  // Updates nums[i] to val equivalently.
  void update(int i, int val) override {
    update(0, 0, n - 1, i, val);
  }

  // Returns sum(nums[i..j]).
  int query(int i, int j) override {
    return query(0, 0, n - 1, i, j);
  }

 private:
  const int n;       // the size of the input array
  vector<int> tree;  // the segment tree

  void build(const vector<int>& nums, int treeIndex, int lo, int hi) {
    if (lo == hi) {
      tree[treeIndex] = nums[lo];
      return;
    }
    const int mid = (lo + hi) / 2;
    const int leftTreeIndex = left(treeIndex);
    const int rightTreeIndex = right(treeIndex);
    build(nums, leftTreeIndex, lo, mid);
    build(nums, rightTreeIndex, mid + 1, hi);
    tree[treeIndex] = merge(tree[leftTreeIndex], tree[rightTreeIndex]);
  }

  void update(int treeIndex, int lo, int hi, int i, int val) {
    if (lo == i && hi == i) {
      tree[treeIndex] = val;
      return;
    }
    const int mid = (lo + hi) / 2;
    const int leftTreeIndex = left(treeIndex);
    const int rightTreeIndex = right(treeIndex);
    if (i <= mid)
      update(leftTreeIndex, lo, mid, i, val);
    else
      update(rightTreeIndex, mid + 1, hi, i, val);
    tree[treeIndex] = merge(tree[leftTreeIndex], tree[rightTreeIndex]);
  }

  int query(int treeIndex, int lo, int hi, int i, int j) {
    // [lo, hi] lies completely inside [i, j].
    if (i <= lo && hi <= j)
      return tree[treeIndex];
    // [lo, hi] lies completely outside [i, j].
    if (j < lo || hi < i)
      return 0;
    const int mid = (lo + hi) / 2;
    return merge(query(left(treeIndex), lo, mid, i, j),
                 query(right(treeIndex), mid + 1, hi, i, j));
  }

  // Merges the result of the left node and the right node.
  int merge(int a, int b) override {
    return a + b;
  }
};

class NumArray {
 public:
  NumArray(vector<int>& nums) : tree(nums) {}

  void update(int index, int val) {
    tree.update(index, val);
  }

  int sumRange(int left, int right) {
    return tree.query(left, right);
  }

 private:
  SegmentTree tree;
};