2019牛客暑期多校训练营(第四场)C sequence —— 笛卡尔树模板+线段树

This way

题意:

问你
在这里插入图片描述

题解:

遇到这种题目一定是先做最小的点所覆盖的区间,依次这样递归下去。这时候就有一个快速知道当前最小的点的位置以及区间的做法:笛卡尔树
以下的讲解是基于顺序为下标,排序为最小值最优。
笛卡尔树就是一个类似二叉搜索树的二叉树,首先用一个单调栈来维护从根开始的最右链,然后每次进来一个位置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=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=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;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/107558645