C.sequence
题意:有两个长度为n的数组a和b,求
max
1
<
=
l
<
=
r
<
=
n
min
(
a
l
.
.
.
r
)
∗
s
u
m
(
b
l
.
.
.
r
)
\max_{1<=l<=r<=n}\min(a_{l...r})*sum(b_{l...r})
max1<=l<=r<=nmin(al...r)∗sum(bl...r)
思路:题解中讲的挺清楚的,对于区间[l,r]无法直接枚举。从另一个角度考虑,一个最小值(记为min_x)会作用于一个区间,那么这个区间里面包含这min_x的子区间的最小值显然还是min_x。然后根据min_x的符号就可以分成三种情况。
1.min_x==0,这个最小值的造成区间的值就是0
2.min_x > 0,这时sum越大值越大,所以找区间的右子区间的最大sum,左子区间的最小sum,相减就是最大的区间和
3.min_x < 0,这时sum越小值越大,所以找区间的右子区间的最小sum,左子区间的最大sum,相减就是最小的区间和
主要问题是如何寻找一个最小值所影响的最大区间,笛卡尔树是一种方法,一个根会影响的区间是子树中最小的下标到最大的下标,正好是要求的最大区间的左右端点。
至于寻找最大sum最小sum,只需要对b数组的前缀和做rmq就好了,st表空间可能开不下了,还是线段树,树状数组之类的吧。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e6+5;
const ll INF=1e18;
template <typename _Tp> inline _Tp read(_Tp&x){
char c11=getchar(),ob=0;x=0;
while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}
ll a[N],b[N],sum[N];
int st[N],top;
int lc[N],rc[N];
bool vis[N];
int ct_rt=0;
ll ans=0;
int n;
void build_ct(){
int tmp;
top=0;
for(int i=1;i<=n;i++){
vis[i]=false;
lc[i]=rc[i]=0;
}
for(int i=1;i<=n;i++){
tmp=top;
while(tmp&&a[st[tmp-1]]>a[i])tmp--;
if(tmp)rc[st[tmp-1]]=i;
if(top>tmp)lc[i]=st[tmp];
st[tmp++]=i;
top=tmp;
}
for(int i=1;i<=n;i++){
vis[lc[i]]=vis[rc[i]]=true;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
ct_rt=i;
return;
}
}
}
#define lson rt<<1
#define rson rt<<1|1
ll maxn[N<<2],minn[N<<2];
void build(int rt,int l,int r){
if(l==r){
maxn[rt]=minn[rt]=sum[l];
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
maxn[rt]=max(maxn[lson],maxn[rson]);
minn[rt]=min(minn[lson],minn[rson]);
}
ll query_max(int rt,int l,int r,int x,int y){
if(l>=x&&r<=y){
return maxn[rt];
}
int mid=(l+r)>>1;
if(y<=mid)return query_max(lson,l,mid,x,y);
else if(x>mid) return query_max(rson,mid+1,r,x,y);
else return max(query_max(lson,l,mid,x,mid),query_max(rson,mid+1,r,mid+1,y));
}
ll query_min(int rt,int l,int r,int x,int y){
if(l>=x&&r<=y){
return minn[rt];
}
int mid=(l+r)>>1;
if(y<=mid)return query_min(lson,l,mid,x,y);
else if(x>mid)return query_min(rson,mid+1,r,x,y);
else return min(query_min(lson,l,mid,x,mid),query_min(rson,mid+1,r,mid+1,y));
}
void dfs(int rt,int l,int r){
if(l>=r)return;
if(a[rt]==0){
ans=max(ans,0ll);
} else if(a[rt]>0){
ll ma=query_max(1,1,n,rt,r);
ll mi=0;
if(rt==1)mi=0;
else if(l==1)mi=min(0ll,query_min(1,1,n,1,rt-1));
else mi=query_min(1,1,n,l-1,rt-1);
ans=max(ans,a[rt]*(ma-mi));
} else{
ll mi=query_min(1,1,n,rt,r);
ll ma=0;
if(rt==1)ma=0;
else if(l==1)ma=max(0ll,query_max(1,1,n,1,rt-1));
else ma=query_max(1,1,n,l-1,rt-1);
ans=max(ans,a[rt]*(mi-ma));
}
dfs(lc[rt],l,rt-1);
dfs(rc[rt],rt+1,r);
}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
build_ct();
ans=-INF;
sum[0]=0ll;
for(int i=1;i<=n;i++){
read(b[i]);
ans=max(ans,b[i]*a[i]);
sum[i]=sum[i-1]+b[i];
}
build(1,1,n);
dfs(ct_rt,1,n);
printf("%lld\n",ans);
return 0;
}