题意:
问你
题解:
遇到这种题目一定是先做最小的点所覆盖的区间,依次这样递归下去。这时候就有一个快速知道当前最小的点的位置以及区间的做法:笛卡尔树
以下的讲解是基于顺序为下标,排序为最小值最优。
笛卡尔树就是一个类似二叉搜索树的二叉树,首先用一个单调栈来维护从根开始的最右链,然后每次进来一个位置i,依次pop直到找到第一个小于等于a[i]的位置,将那个点的右儿子标为i,i的左儿子为刚才栈中第一个大于i的位置。
void build(){
for(int i=1;i<=n;i++){
while(top&&a[st[top]]>a[i])
ls[i]=st[top],top--;
fa[i]=st[top];
fa[ls[i]]=i;
if(fa[i])rs[fa[i]]=i;
st[++top]=i;
}
}
然后从根就是st[1],从根开始dfs,对于当前的点,如果a[root]<0,那么b需要尽量小,就在root~r区间找到前缀和的最小值,l-1~root-1区间找到一个最大值。此时有几种情况需要特判。
反之亦然。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e6+5;
const ll inf=5e18;
int ls[N],rs[N],st[N],top,fa[N];
ll a[N],b[N],mx[N*4],mi[N*4];
int n;
void build(){
for(int i=1;i<=n;i++){
while(top&&a[st[top]]>a[i])
ls[i]=st[top],top--;
fa[i]=st[top];
fa[ls[i]]=i;
if(fa[i])rs[fa[i]]=i;
st[++top]=i;
}
}
void build(int l,int r,int root){
if(l==r){
mx[root]=mi[root]=b[l];
return ;
}
int mid=l+r>>1;
build(l,mid,root<<1),build(mid+1,r,root<<1|1);
mi[root]=min(mi[root<<1],mi[root<<1|1]);
mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
ll q_mx(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr)
return mx[root];
ll ans=-inf;
int mid=l+r>>1;
if(mid>=ql)
ans=q_mx(l,mid,root<<1,ql,qr);
if(mid<qr)
ans=max(ans,q_mx(mid+1,r,root<<1|1,ql,qr));
return ans;
}
ll q_mi(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr)
return mi[root];
ll ans=inf;
int mid=l+r>>1;
if(mid>=ql)
ans=q_mi(l,mid,root<<1,ql,qr);
if(mid<qr)
ans=min(ans,q_mi(mid+1,r,root<<1|1,ql,qr));
return ans;
}
ll ans=-inf;
void dfs(int l,int r,int root){
if(l==r){
ans=max(ans,(b[r]-b[l-1])*a[root]);
return ;
}
if(a[root]<0){
ll mi=q_mi(1,n,1,root,r),mx;
if(root==1)mx=0;
else if(l==1)mx=max(0ll,q_mx(1,n,1,l,root-1));
else mx=q_mx(1,n,1,l-1,root-1);
ans=max(ans,a[root]*(mi-mx));
}
else {
ll mx=q_mx(1,n,1,root,r),mi;
if(root==1)mi=0;
else if(l==1)mi=min(0ll,q_mi(1,n,1,l,root-1));
else mi=q_mi(1,n,1,l-1,root-1);
ans=max(ans,a[root]*(mx-mi));
}
if(ls[root])
dfs(l,root-1,ls[root]);
if(rs[root])
dfs(root+1,r,rs[root]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)scanf("%lld",&b[i]),b[i]+=b[i-1];
build();
build(1,n,1);
dfs(1,n,st[1]);
printf("%lld\n",ans);
return 0;
}