Using Segmented tree with explanation easy to understand
\n# Segment tree node\nclass Node(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n        self.total = 0\n   
```\n# Segment tree node\nclass Node(object):\n    def __init__(self, start, end):\n        self.start = start\n        self.end = end\n        self.total = 0\n        self.left = None\n        self.right = None\n\n\nclass NumArray(object):\n\n    def __init__(self, nums):\n        # helper function to create the tree from input array\n        def createTree(nums, l, r):\n\n            # base case\n            if l > r:\n                return None\n\n            # leaf node\n            if l == r:\n                n = Node(l, r)\n                n.total = nums[l]\n                return n\n\n            mid = (l + r) // 2\n\n            root = Node(l, r)\n\n            # recursively build the Segment tree\n            root.left = createTree(nums, l, mid)\n            root.right = createTree(nums, mid + 1, r)\n\n            # Total stores the sum of all leaves under root\n            # i.e. those elements lying between (start, end)\n            root.total = root.left.total + root.right.total\n\n            return root\n\n        self.root = createTree(nums, 0, len(nums) - 1)\n\n    def update(self, i, val):\n        # Helper function to update a value\n        def updateVal(root, i, val):\n\n            # Base case. The actual value will be updated in a leaf.\n            # The total is then propogated upwards\n            if root.start == root.end:\n                root.total = val\n                return val\n\n            mid = (root.start + root.end) // 2\n\n            # If the index is less than the mid, that leaf must be in the left subtree\n            if i <= mid:\n                updateVal(root.left, i, val)\n\n            # Otherwise, the right subtree\n            else:\n                updateVal(root.right, i, val)\n\n            # Propogate the changes after recursive call returns\n            root.total = root.left.total + root.right.total\n\n            return root.total\n\n        return updateVal(self.root, i, val)\n\n    def sumRange(self, i, j):\n        # Helper function to calculate range sum\n        def rangeSum(root, i, j):\n\n            # If the range exactly matches the root, we already have the sum\n            if root.start == i and root.end == j:\n                return root.total\n\n            mid = (root.start + root.end) // 2\n\n            # If end of the range is less than the mid, the entire interval lies\n            # in the left subtree\n            if j <= mid:\n                return rangeSum(root.left, i, j)\n\n            # If start of the interval is greater than mid, the entire inteval lies\n            # in the right subtree\n            elif i >= mid + 1:\n                return rangeSum(root.right, i, j)\n\n            # Otherwise, the interval is split. So we calculate the sum recursively,\n            # by splitting the interval\n            else:\n                return rangeSum(root.left, i, mid) + rangeSum(\n                    root.right, mid + 1, j\n                )\n\n        return rangeSum(self.root, i, j)\n\n# Your NumArray object will be instantiated and called as such:\n# obj = NumArray(nums)\n# obj.update(index,val)\n# param_2 = obj.sumRange(left,right)\n\n```
['Binary Search', 'Python', 'Python3']