POJ2796 Feel Good【单调栈】

题意:求 区间元素和 * 区间内最小值 的最大值


思路:一般的方法是对于某一元素,向左向右求一连续区间,区间内的点不小于这个元素,会TLE

开一个单调不递减栈。L[i] 表示i这个元素,左区间的端点。R[i] 类似

当 当前的元素 i ≥ 栈顶的元素,直接入栈,L[i] = i

当前的元素 i < 栈顶的元素,弹出所有比它大的元素k,每个弹出元素的 R[k] = i - 1

当前元素i入栈,L[i] = 最后一个弹出元素k的 L[k]


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+5; 

struct data
{
	int val;
	int l,r;
}node[maxn];
ll sum[maxn],ans;
int a,b;
int st[maxn],top;

ll cal(int x)
{
	ll s = (ll)node[x].val * (sum[node[x].r] - sum[ node[x].l -1]);
	return s;
}

int main(void)
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		sum[0] = 0;
		for(int i = 1; i <= n; i++)
		{
			scanf("%d",&node[i].val);
			sum[i] = sum[i-1] + node[i].val;
		}
		top = -1;
		ans = -1;
		for(int i = 1; i <= n; i++)
		{
			if(top < 0)
			{
				node[i].l = i;
				st[++top] = i;
				continue;
			}
			int flag = 0;
			while(top >= 0 && node[ st[top] ].val > node[i].val)
			{
				flag = 1;
				node[ st[top] ].r = i-1;
				ll tp = cal(st[top]);
				if(tp > ans)
				{
					ans = tp;
					a = node[ st[top] ].l;
					b = node[ st[top] ].r;
				}
				top--;
			}
			if(flag)
				node[i].l = node[st[top+1]].l;
			else
				node[i].l = i;
			st[++top] = i;
		}
		while(top >= 0)
		{
			node[st[top]].r = n;
			ll tp = cal(st[top]);
			if(tp > ans)
			{
				ans = tp;
				a = node[ st[top] ].l;
				b = node[ st[top] ].r;
			}
			top--;
		}
		printf("%lld\n%d %d\n",ans,a,b);
	}
	return 0;
}



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