单调栈的性质及应用

ZZULI  XXX

题意:给你一串序列,要你求所有子序列的最小值之和。(n很大,无法暴力)

思路:完美的单调栈模板

这里简要介绍下单调栈的性质,(其他的都没用)

单调栈的维护是 O(n) 级的时间复杂度,因为所有元素只会进入栈一次,并且出栈后再也不会进栈了。

单调栈的性质:

1.单调栈里的元素具有单调性

2.元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除

3.使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。

(也就是说在元素进栈前他向左拓展的区间已经确定,在出栈前她能向右拓展的区间也能确定)

代码如下:

#include     
#include            
#include            
#include    
#include  
#include            
#include            
#include            
#include            
#include    
#include   
#include    
using namespace std;
typedef long long  ll;
#define inf  1000000000       
#define mod 1000000007             
#define maxn  286000  
#define PI 3.1415926
#define lowbit(x) (x&-x)            
#define eps 1e-9  
struct node
{
	long long x, y, l, r;
}str[maxn];
stackt;
int  main()
{
	long long  T, i, j, n, m, k, sum;
	scanf("%lld", &T);
	while (T--)
	{
		sum = 0;
		scanf("%lld", &n);
		for (i = 1;i <= n;i++)
		{
			scanf("%lld", &str[i].x);
			str[i].y = i;
		}
		for (i = 1;i <= n;i++)
		{
			str[i].l = i;
			while (t.empty() == 0 && t.top().x>str[i].x)
			{
				str[t.top().y].r = i - 1;
				str[i].l = str[t.top().y].l;
				t.pop();
			}
			t.push(str[i]);
		}
		while (t.empty() == 0)
		{
			str[t.top().y].r = n;
			t.pop();
		}
		for (i = 1;i <= n;i++)
			sum += str[i].x*(i - str[i].l + 1)*(str[i].r - i + 1);
		printf("%lld\n", sum);
	}
}





你可能感兴趣的:(单调栈)