zoukankan      html  css  js  c++  java
  • 洛谷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<bits/stdc++.h>
    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{
        vector<no>a;
        int p,v;
        void ad(no x){
            a.push_back(x);
            v++;
        }
        void bd(){
            tp=0;
            for(int i=0;i<v;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<tp;i++)
                a[i]=st[i];
        }
        int fd(int x){
            while(p+1<v&&a[p].x*x+a[p].y<=a[p+1].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<<y.x<<' '<<y.y<<'
    ';
        cout<<'
    ';
    }
    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+1<x.v&&j+1<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(i<x.v&&j<y.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(r<x||y<l)return (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<<ans[i]<<'
    ';
    }
  • 相关阅读:
    qq
    构造方法
    Java模块化开发
    q
    qqq
    qq
    qqq
    Git服务器搭建及SSH无密码登录设置
    php面向对象中的魔术方法中文说明
    计算机中丢失 msvcr110.dll 怎么办
  • 原文地址:https://www.cnblogs.com/cszmc2004/p/13181302.html
Copyright © 2011-2022 走看看