import java.util.Deque;
import java.util.LinkedList;
/** 参考链接:https://leetcode.cn/problems/sum-of-subarray-minimums/solutions/1930857/gong-xian-fa-dan-diao-zhan-san-chong-shi-gxa5/
* https://leetcode.cn/problems/sum-of-subarray-minimums/solutions/1931139/-by-muse-77-367z/
* 单调栈
* 思路:将求取每个连续的子数组的最小值之和,转换为求:以每个数为最小值然后求以该数
* 为最小值子数组的个数,然后个数乘以该最小值得到的数加到结果集中。重复这样的
* 操作遍历全部的数。
*
* 问题:如何找到以该数为最小值的数组个数。
* 想要解决这个问题,需要明白 乘法原理: 最小值左边的数乘以右边的数等于该数全部的连续子序列的个数
*
* 栈中存储的全部是下标,但数值是从栈底到栈顶是单调递增的。
*
*
* @auther start
* @create 2023-11-26 21:35
*/
public class L907 {
private static final long MOD = (long) 1e9 + 7;
public int sumSubarrayMins(int[] arr) {
long ans = 0;
Deque<Integer> st = new LinkedList<>();
st.push(-1);
for (int r = 0; r <= arr.length; r++) {
int x = r < arr.length ? arr[r] : -1;
// x 小于栈顶元素,栈顶元素出栈,新的栈顶元素是该元素的
// 左边界,r是该元素的有边界。
while (st.size() > 1 && arr[st.peek()] >= x) {
int i = st.pop();
//将该最小值组成的元素个数乘以该最小值的结果添加到结果集中。
ans += (long) arr[i] * (i - st.peek()) * (r - i);
}
st.push(r);
}
//输出结果
return (int) (ans % MOD);
}
}