1 条题解

  • 0
    @ 2025-8-24 22:13:29

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar qwaszx
    不再为往事受困.

    搬运于2025-08-24 22:13:29,当前版本为作者最后更新于2020-08-28 13:59:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先,欢迎加入EI队长粉丝裙:450567214

    本题的一个 O((n+m)log3n+qlogn)O((n+m)\log^3 n+q\log n) 做法由 EI 队长在她的集训队论文《浅谈函数最值的动态维护》中给出,其中 n,m,qn,m,q 分别代表序列长度、修改次数、查询次数. 该数据结构被称为 Kinetic Tournament 树 (KTT).

    该做法的原理在 EI's blog 或论文中有详细阐述,这里仅给出一个直接实现及可参考的代码.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=400500;
    const long long INF=2e18;
    int n,w[N],m;
    long long tag[N<<2];
    struct LINE//一次函数
    {
        int k;long long b;
        LINE operator +(const LINE &a)const{return (LINE){k+a.k,b+a.b};}
    };
    pair<LINE,long long> max(LINE a,LINE b)//对两个一次函数取x=0时的最值,同时给出max的选取不发生变化的最大值C(即 x>C 时max变成另一个)
    {
        if(a.k<b.k||(a.k==b.k&&a.b<b.b))swap(a,b);
        if(a.b>=b.b){return make_pair(a,INF);}
        return make_pair(b,(b.b-a.b)/(a.k-b.k));
    }
    struct Node
    {
        LINE ls,rs,ans,sum;long long x;//增量>x时子树内会有max的选取发生变化
        Node operator +(const Node &a)const
        {
            Node t;t.x=min(x,a.x);
            pair<LINE,long long>tmp=max(ls,sum+a.ls);
            t.ls=tmp.first,t.x=min(t.x,tmp.second);
            tmp=max(a.rs,rs+a.sum);
            t.rs=tmp.first,t.x=min(t.x,tmp.second);
            tmp=max(ans,a.ans);t.x=min(t.x,tmp.second);
            tmp=max(tmp.first,rs+a.ls);
            t.ans=tmp.first,t.x=min(t.x,tmp.second);
            t.sum=sum+a.sum;
            return t;
        }
    }a[N<<2];
    void build(int rot,int lt,int rt)
    {
        if(lt==rt)
        {
            LINE t={1,w[lt]};
            a[rot]=(Node){t,t,t,t,INF};
            return;
        }
        int mid=(lt+rt)>>1;
        build(rot<<1,lt,mid),build(rot<<1|1,mid+1,rt);
        a[rot]=a[rot<<1]+a[rot<<1|1];
    }
    void upd(int rot,long long w)
    {
        tag[rot]+=w;a[rot].x-=w;
        a[rot].ls.b+=a[rot].ls.k*w;
        a[rot].rs.b+=a[rot].rs.k*w;
        a[rot].ans.b+=a[rot].ans.k*w;
        a[rot].sum.b+=a[rot].sum.k*w;
    }
    void upd(int rot,int lt,int rt,long long w)
    {
        if(w>a[rot].x)//如果增量使得子树内有max发生变化则递归下去重构
        {
            long long t=tag[rot]+w;tag[rot]=0;int mid=(lt+rt)>>1;
            upd(rot<<1,lt,mid,t),upd(rot<<1|1,mid+1,rt,t);
            a[rot]=a[rot<<1]+a[rot<<1|1];
        }
        else upd(rot,w);
    }
    void pushdown(int rot)
    {
        if(tag[rot])
        {
            long long t=tag[rot];tag[rot]=0;
            upd(rot<<1,t),upd(rot<<1|1,t);
        }
    }
    void update(int rot,int lt,int rt,int lq,int rq,int x)
    {
        if(lt>=lq&&rt<=rq){upd(rot,lt,rt,x);return;}
        pushdown(rot);
        int mid=(lt+rt)>>1;
        if(lq<=mid)update(rot<<1,lt,mid,lq,rq,x);
        if(rq>mid)update(rot<<1|1,mid+1,rt,lq,rq,x);
        a[rot]=a[rot<<1]+a[rot<<1|1];
    }
    Node query(int rot,int lt,int rt,int lq,int rq)
    {
        if(lt>=lq&&rt<=rq)return a[rot];
        pushdown(rot);
        int mid=(lt+rt)>>1;
        if(rq<=mid)return query(rot<<1,lt,mid,lq,rq);
        if(lq>mid)return query(rot<<1|1,mid+1,rt,lq,rq);
        return query(rot<<1,lt,mid,lq,mid)+query(rot<<1|1,mid+1,rt,mid+1,rq);
    }
    int getin()
    {
        int x=0,f=1;char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
        return x*f;
    }
    int main()
    {
        n=getin(),m=getin();
        for(int i=1;i<=n;i++)w[i]=getin();
        build(1,1,n);
        for(int i=1,opt,l,r,x;i<=m;i++)
        {
            opt=getin(),l=getin(),r=getin();
            if(opt==1)x=getin(),update(1,1,n,l,r,x);
            else printf("%lld\n",max(0ll,query(1,1,n,l,r).ans.b));
        }
    }
    
    • 1

    信息

    ID
    4747
    时间
    1800ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者