2
def subArrayRanges(self, nums: List[int]) -> int:5
# the answer will be sum{ Max(subarray) - Min(subarray) } over all possible subarray6
# which decomposes to sum{Max(subarray)} - sum{Min(subarray)} over all possible subarray7
# so totalsum = maxsum - minsum8
# we calculate minsum and maxsum in two different loops11
# first calculate sum{ Min(subarray) } over all subarrays12
# sum{ Min(subarray) } = sum(f(i) * nums[i]) ; i=0..n-113
# where f(i) is number of subarrays where nums[i] is the minimum value14
# f(i) = (i - index of the previous smaller value) * (index of the next smaller value - i) * nums[i]15
# we can claculate these indices in linear time using a monotonically increasing stack.17
for next_smaller in range(n + 1):18
# we pop from the stack in order to satisfy the monotonically increasing order property19
# if we reach the end of the iteration and there are elements present in the stack, we pop all of them20
while stack and (next_smaller == n or nums[stack[-1]] > nums[next_smaller]):22
prev_smaller = stack[-1] if stack else -123
minsum += nums[i] * (next_smaller - i) * (i - prev_smaller)24
stack.append(next_smaller)26
# then calculate sum{ Max(subarray) } over all subarrays27
# sum{ Max(subarray) } = sum(f'(i) * nums[i]) ; i=0..n-128
# where f'(i) is number of subarrays where nums[i] is the maximum value29
# f'(i) = (i - index of the previous larger value) - (index of the next larger value - i) * nums[i]30
# this time we use a monotonically decreasing stack.32
for next_larger in range(n + 1):33
# we pop from the stack in order to satisfy the monotonically decreasing order property34
# if we reach the end of the iteration and there are elements present in the stack, we pop all of them35
while stack and (next_larger == n or nums[stack[-1]] < nums[next_larger]):37
prev_larger = stack[-1] if stack else -138
maxsum += nums[i] * (next_larger - i) * (i - prev_larger)39
stack.append(next_larger)41
return maxsum - minsum