【单调栈】zjoj p1859子序列累加和

以前刚学的时候不会,补上去;用四个单调栈求出每个数在加或减的时候计算进的次数就好。

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define ll long long 
using namespace std;
ll num[400000];
ll a[400000],b[400000],c[400000],d[400000];
ll top=0;
ll    ak[400000],bk[400000],ck[400000],dk[400000];
int main()
{
	//memset(ak,1,sizeof(ak));
	//memset(bk,1,sizeof(bk));
	//memset(ck,1,sizeof(ck));
	//memset(dk,1,sizeof(dk));
	//freopen("a.in","r",stdin);
	ll n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>num[i];
	}
	for(int i=1;i<=n;i++)
	{
		ak[i]=1;
		int w=top+1;
		while(num[i]>=num[a[top]]&&top!=0)
		{
			ak[i]+=ak[a[top]];
			top--;
		}
		a[++top]=i;
	}
	top=0;
	for(int i=n;i>0;i--)
	{
		bk[i]=1;
		int w=top+1;
		while(num[i]>num[b[top]]&&top!=0)
		{
			bk[i]+=bk[b[top]];
			top--;
		}
		b[++top]=i;
	}
	top=0;
	for(int u=1;u<=n;u++)
	{
		ck[u]=1;
		int w=top+1;
		while(num[u]<=num[c[top]]&&top!=0)
		{
			ck[u]+=ck[c[top]];
			top--;
		}
		c[++top]=u;
	}
	int top=0;
	for(int u=n;u>=1;u--)
	{
		dk[u]=1;
		int w=top+1;
		while(num[u]<num[d[top]]&&top!=0)
		{
			dk[u]+=dk[d[top]];
			top--;
		}
		d[++top]=u;
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		ll w=ak[i]*bk[i]*num[i];
		ll q=ck[i]*dk[i]*num[i];
		ans+=w-q;
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2017-03-12 21:44  Fornic  阅读(320)  评论(0编辑  收藏  举报