1. 程式人生 > >單調棧的性質及應用

單調棧的性質及應用

ZZULI  XXX

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

思路:完美的單調棧模板

這裡簡要介紹下單調棧的性質,(其他的都沒用)

單調棧的維護是 O(n) 級的時間複雜度,因為所有元素只會進入棧一次,並且出棧後再也不會進棧了。

單調棧的性質:

1.單調棧裡的元素具有單調性

2.元素加入棧前,會在棧頂端把破壞棧單調性的元素都刪除

3.使用單調棧可以找到元素向左遍歷第一個比他小的元素,也可以找到元素向左遍歷第一個比他大的元素。

(也就是說在元素進棧前他向左拓展的區間已經確定,在出棧前她能向右拓展的區間也能確定)

程式碼如下:

#include<map>     
#include<stack>            
#include<queue>            
#include<vector>    
#include<string>  
#include<math.h>            
#include<stdio.h>            
#include<iostream>            
#include<string.h>            
#include<stdlib.h>    
#include<algorithm>   
#include<functional>    
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];
stack<node>t;
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);
	}
}