【单调栈】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;
}

浙公网安备 33010602011771号