public void GivenMinBinaryIndexedTreeWhenUpdateChangeValueThenIntervalUpdated()
        {
            var data = Enumerable.Range(1, 200).ToArray();
            var tree = new BinaryIndexedTree <int>(data,
                                                   (a, b) => Math.Min(a, b),
                                                   (a, b) =>
            {
                if (a > b)
                {
                    throw new Exception("Can only decrease value");
                }
                return(Math.Min(a, b));
            },
                                                   int.MaxValue
                                                   );

            for (int i = 0; i < data.Length; i++)
            {
                int min = int.MaxValue;
                for (int j = i; j < data.Length; j++)
                {
                    min = Math.Min(min, data[j]);
                    Assert.Equal(min, tree.GetOperationValueOnInterval(i, j));
                }
            }
        }
        public void GivenRandomSumBinaryIndexedTreeWhenUpdateValuesThenIntervalReturnsCorrectValues()
        {
            var rand = new Random();
            var data = new uint[64];

            for (int i = 0; i < data.Length; i++)
            {
                data[i] = (uint)rand.Next();
            }
            var tree = new BinaryIndexedTree <uint>(data, (a, b) => a + b, (a, b) => a - b);

            for (int i = 0; i < data.Length; i++)
            {
                var elem = (uint)rand.Next();
                data[i] = elem;
                tree[i] = elem;
            }

            for (int i = 0; i < data.Length; i++)
            {
                uint sum = 0;
                for (int j = i; j < data.Length; j++)
                {
                    sum += data[j];
                    Assert.Equal(sum, tree.GetOperationValueOnInterval(i, j));
                }
            }
        }
        public void GivenBinaryIndexedTreeWithSelectorWhenCreateTreeThenNoException()
        {
            var tree = new BinaryIndexedTree <Stub, int>(new[] { new Stub()
                                                                 {
                                                                     A = 1, B = 1
                                                                 }, new Stub()
                                                                 {
                                                                     A = 100, B = 2
                                                                 } }, Plus, Minus, (x) => x.B);

            Assert.Equal(3, tree.GetOperationValueOnInterval(0, 1));
        }
        public void GivenSumBinaryIndexedTreeWhenAskOperationOnIntervalThenReturnCorrectValues()
        {
            var data = Enumerable.Range(1, 200).ToArray();
            var tree = new BinaryIndexedTree <int, int>(data, (a, b) => a + b, (a, b) => a - b, (x) => x);

            for (int i = 0; i < data.Length; i++)
            {
                int sum = 0;
                for (int j = i; j < data.Length; j++)
                {
                    sum += data[j];
                    Assert.Equal(sum, tree.GetOperationValueOnInterval(i, j));
                }
            }
        }
        public void GivenSumBinaryIndexedTreeWhenUpdateChangeValueThenIntervalUpdated()
        {
            var data = Enumerable.Range(1, 200).ToArray();
            var tree = new BinaryIndexedTree <int, int>(data, (a, b) => a + b, (a, b) => a - b, (x) => x);

            data[10] = 100;
            tree[10] = 100;
            for (int i = 0; i < data.Length; i++)
            {
                int sum = 0;
                for (int j = i; j < data.Length; j++)
                {
                    sum += data[j];
                    Assert.Equal(sum, tree.GetOperationValueOnInterval(i, j));
                }
            }
        }
        public void GivenBinaryIndexedTreeWheTryIntervalOutsideOfRangeThenThrowException(int left, int right)
        {
            var tree = new BinaryIndexedTree <int>(new[] { 1, 2, 3, 4 }, Plus, Minus);

            Assert.Throws <ArgumentOutOfRangeException>(() => tree.GetOperationValueOnInterval(left, right));
        }