package com.freetymekiyan.algorithms.level.medium;

import org.junit.Test;

/**
 * Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
 * <p>
 * The update(i, val) function modifies nums by updating the element at index i to val.
 * <p>
 * Example:
 * Given nums = [1, 3, 5]
 * <p>
 * sumRange(0, 2) -> 9
 * update(1, 2)
 * sumRange(0, 2) -> 8
 * Note:
 * The array is only modifiable by the update function.
 * You may assume the number of calls to update and sumRange function is distributed evenly.
 * <p>
 * Tags: Segment Tree, Binary Indexed Tree
 * Similar Problems: (E) Range Sum Query - Immutable, (H) Range Sum Query 2D - Mutable
 */
public class RangeSumQueryMutable {

    public class NumArray {

        private final int[] nums;
        private final int[] BiTree;
        private final int n;

        public NumArray(int[] nums) {
            this.nums = nums;
            n = nums.length;
            BiTree = new int[n + 1];
            for (int i = 0; i < n; i++) {
                init(i, nums[i]);
            }
        }

        private void init(int i, int val) {
            i++;
            while (i <= n) {
                BiTree[i] += val;
                i += (i & -i);
            }
        }

        void update(int i, int val) {
            int diff = val - nums[i];
            nums[i] = val;
            init(i, diff);
        }

        private int getSum(int i) {
            i++;
            int sum = 0;
            while (i > 0) {
                sum += BiTree[i];
                i -= (i & -i);
            }
            return sum;
        }

        public int sumRange(int i, int j) {
            return getSum(j) - getSum(i - 1);
        }
    }

// Your NumArray object will be instantiated and called as such:
// NumArray numArray = new NumArray(nums);
// numArray.sumRange(0, 1);
// numArray.update(1, 10);
// numArray.sumRange(1, 2);


    @Test
    public void testExamples() {
        int[] input = {1, 3, 5};
        NumArray n = new NumArray(input);
        System.out.println(n.sumRange(0, 2));
        n.update(1, 2);
        System.out.println(n.sumRange(0, 2));
    }
}

add Range Sum Query Mutable