洛谷5073

常数不想卡了。。。。。。

题目要全局加和区间最大子段和。

单点加和区间最大子段和可以维护前缀/后缀max和,总体和,最大子段和解决。

现在要求全局加也能这样维护。

但是实际上一个前缀/后缀在加了一定程度后可能不再是答案。比较麻烦。

解决方法:

我们想要快速寻找到一些后缀的最优决策点。

假设当前的后缀长度为$k$,值为$b$

根据题意,加了以后的值就为$kx+b$,其实就是一条直线。

这个比较难维护(原因见后)。可以把这个后缀化成一个点$(x,y)$,如果全局加了$x$,则答案就是一条直线$-x$切这个凸包,且询问最大截距。

答案必须要在凸包上。可以建出凸包。

这样子成功维护了前/后缀的答案。

但是全局答案十分难维护。

当前节点x的全局答案就是它的左/右子树内部的全局答案的凸包,再加上线段树左半边取出的任意一个点$(x,y)$和右半边取出任意的点$(a,b)$的$(x+y,a+b)$这些点组成的凸包。

每一个节点上取出左/右子树如果从线段树每一个节点上取出左/右子树取出后/前缀暴力合并再求凸包,时间复杂度高达$O(n^2)$,不可接受。

注意到答案就是左/右子树的后/前缀的闵可夫斯基和加上左/右子树的答案,所以对左/右节点的凸包求闵可夫斯基和即可。

如果在线段树询问定位到的节点的每个凸包上二分,则时间复杂度为$O((n+m)\log^2_2n)$,很难过。

可以把所有点按照询问的全局加值从小到大排序,这样子最优决策点就是单调增加的,时间复杂度降为$O((n+m)\log_2n)$

代码比较难写。

下面的代码由于常数原因只能获得10分,但是正确性有保障。

#include
using namespace std;
#define int long long
#define N 1200010
struct no{
    int x,y;
}st[N],tv[N];
int tp,n,m,a[N],ct,ans[N],s[N],mx[N];

no operator +(no x,no y){
    return (no){x.x+y.x,x.y+y.y};
}
no operator -(no x,no y){
    return (no){x.x-y.x,x.y-y.y};
}
int operator <=(no x,no y){
    return x.y*y.x<=x.x*y.y;
}
int rd(){
    int v=0,op=1;
    char c=getchar();
    while(!isdigit(c)&&c!='-')
        c=getchar();
    if(c=='-'){
        op=-op;
        c=getchar();
    }
    while(isdigit(c)){
        v=v*10+c-'0';
        c=getchar();
    }
    return v*op;
}
struct hl{
    vectora;
    int p,v;
    void ad(no x){
        a.push_back(x);
        v++;
    }
    void bd(){
        tp=0;
        for(int i=0;i){
            if(!tp){
                st[tp++]=a[i];
                continue;
            }
            if(tp&&st[tp-1].x==a[i].x){
                if(st[tp-1].y<=a[i].y){
                    tp--;
                    st[tp++]=a[i];
                }
                continue;
            }
            while(tp>1&&(st[tp-1]-st[tp-2])<=(a[i]-st[tp-2]))
                tp--;
            st[tp++]=a[i];
        }
        v=tp;
        a.resize(tp);
        for(int i=0;i)
            a[i]=st[i];
    }
    int fd(int x){
        while(p+11].x*x+a[p+1].y)
            p++;
        return a[p].x*x+a[p].y;
    }
}sh[N],ph[N],sv[N];
hl r;
void deb(hl x){
    for(no y:x.a)
        cout<' '<'\n';
    cout<<'\n';
}
hl operator +(hl x,hl y){
    //deb(x);
    //deb(y);
    r.p=r.v=0;
    r.a.clear();
    r.ad(x.a[0]+y.a[0]);
    int i=0,j=0,ct=0;
    while(i+11<y.v){
        if((y.a[j+1]-y.a[j])<=(x.a[i+1]-x.a[i])){
            i++;
            r.ad(x.a[i]+y.a[j]);
        }
        else{
            j++;
            r.ad(x.a[i]+y.a[j]);
        }
    }
    while(i+1<x.v){
        i++;
        r.ad(x.a[i]+y.a[j]);
    }
    while(j+1<y.v){
        j++;
        r.ad(x.a[i]+y.a[j]);
    }
    r.v=r.a.size();
    //deb(r);
    return r;
}
struct qu{
    int l,r,x,i;
}q[N];
struct nc{
    int ls,rs,s,mx;
};
nc operator +(nc x,nc y){
    nc r=(nc){0,0,0,0};
    r.s=x.s+y.s;
    r.ls=max(x.ls,y.ls+x.s);
    r.ls=max(r.ls,0ll);
    r.rs=max(y.rs,x.rs+y.s);
    r.rs=max(r.rs,0ll);
    r.mx=max(x.mx,max(y.mx,x.rs+y.ls));
    r.mx=max(r.mx,0ll);
    return r;
}
int operator <(qu x,qu y){
    return x.x<y.x;
}
hl mg(hl x,hl y){
    r.p=r.v=0;
    r.a.clear();
    int i=0,j=0;
    while(iy.v){
        if(x.a[i].x<y.a[j].x){
            r.a.push_back(x.a[i]);
            i++;
        }
        else{
            r.a.push_back(y.a[j]);
            j++;
        }
    }
    while(i<x.v){
        r.a.push_back(x.a[i]);
        i++;
    }
    while(j<y.v){
        r.a.push_back(y.a[j]);
        j++;
    }
    r.bd();
    r.v=r.a.size();
    return r;
}
void bd(int o,int l,int r){
    if(l==r){
        sh[o].ad((no){0,0});
        sh[o].ad((no){1,a[l]});
        ph[o].ad((no){0,0});
        ph[o].ad((no){1,a[l]});
        sv[o].ad((no){0,0});
        sv[o].ad((no){1,a[l]});
        s[o]=a[l];
        return;
    }
    int md=(l+r)/2;
    bd(o*2,l,md);
    bd(o*2+1,md+1,r);
    int sg=0;
    sh[o].ad((no){0,0});
    for(int i=r;i>=l;i--){
        sg+=a[i];
        sh[o].ad((no){r-i+1,sg});
    }
    sg=0;
    ph[o].ad((no){0,0});
    for(int i=l;i<=r;i++){
        sg+=a[i];
        ph[o].ad((no){i-l+1,sg});
    }
    ph[o].bd();
    sh[o].bd();
    if(o==1){
        o++;
        o--;
    }
    sv[o]=mg(mg(sv[o*2],sv[o*2+1]),sh[o*2]+ph[o*2+1]);
    //deb(sv[o]);
    s[o]=s[o*2]+s[o*2+1];
}
nc qq(int o,int l,int r,int x,int y,int z){
    if(rreturn (nc){0,0,0,0};
    if(x<=l&&r<=y){
        nc v=(nc){ph[o].fd(z),sh[o].fd(z),z*(r-l+1)+s[o],sv[o].fd(z)};
        return v;
    }
    int md=(l+r)/2;
    nc r1=qq(o*2,l,md,x,y,z);
    nc r2=qq(o*2+1,md+1,r,x,y,z);
    return r1+r2;
}
signed main(){
    //freopen("ww.out","r",stdin);
    //freopen("t.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        a[i]=rd();
    bd(1,1,n);
    int p=0;
    for(int i=1;i<=m;i++){
        int t,x,y;
        t=rd();
        if(t==1){
            x=rd();
            p+=x;
        }
        else{
            x=rd();
            y=rd();
            q[++ct]={x,y,p,ct};
        }
    }
    sort(q+1,q+ct+1);
    for(int i=1;i<=ct;i++)
        ans[q[i].i]=qq(1,1,n,q[i].l,q[i].r,q[i].x).mx;
    for(int i=1;i<=ct;i++)
        cout<'\n';
}

 

你可能感兴趣的:(洛谷5073)