https://ac.nowcoder.com/acm/contest/884/C
听说这题是笛卡尔树,发现去年这题是队友写的,来补一补
然而完全不想用笛卡尔树写,单调栈多爽
对于a[i],找出他为最小的l[i]和r[i],然后如果a[i]<0,就跨过i的找前缀和相减最小值,否则则找区间和最大值
辣鸡题目卡st表要写线段树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e6+10;
int n,k;ll ans;
int a[maxl],b[maxl],s[maxl],l[maxl],r[maxl];
ll sum[maxl];
struct node
{
int l,r;ll mi,mx;
}tr[maxl<<2];
inline void build(int k,int l,int r)
{
tr[k].l=l;tr[k].r=r;
if(l==r)
{
tr[k].mi=tr[k].mx=sum[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tr[k].mi=min(tr[k<<1].mi,tr[k<<1|1].mi);
tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
sum[i]=sum[i-1]+b[i];
}
build(1,0,n);
}
inline ll getmx(int k,int l,int r)
{
if(tr[k].l==l && tr[k].r==r)
return tr[k].mx;
int mid=(tr[k].l+tr[k].r)>>1;
if(r<=mid)
return getmx(k<<1,l,r);
else if(l>mid)
return getmx(k<<1|1,l,r);
else
return max(getmx(k<<1,l,mid),getmx(k<<1|1,mid+1,r));
}
inline ll getmi(int k,int l,int r)
{
if(tr[k].l==l && tr[k].r==r)
return tr[k].mi;
int mid=(tr[k].l+tr[k].r)>>1;
if(r<=mid)
return getmi(k<<1,l,r);
else if(l>mid)
return getmi(k<<1|1,l,r);
else
return min(getmi(k<<1,l,mid),getmi(k<<1|1,mid+1,r));
}
inline void mainwork()
{
int top=0;s[0]=0;
for(int i=1;i<=n;i++)
{
while(top>0 && a[i]<=a[s[top]])
top--;
s[++top]=i;l[i]=s[top-1]+1;
}
top=0;s[0]=n+1;
for(int i=n;i>=1;i--)
{
while(top>0 && a[i]<=a[s[top]])
top--;
s[++top]=i;r[i]=s[top-1]-1;
}
ll rs,ls;ans=0;
for(int i=1;i<=n;i++)
if(a[i]<0)
{
ls=getmx(1,l[i]-1,i-1);
rs=getmi(1,i,r[i]);
ans=max(ans,(rs-ls)*a[i]);
}
else
{
ls=getmi(1,l[i]-1,i-1);
rs=getmx(1,i,r[i]);
ans=max(ans,(rs-ls)*a[i]);
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}