• Ynoi2018 末日时在做什么?有没有空?可以来拯救吗?


    Link
    这个是(O(nsqrt{nlog n}))的过不去的辣鸡做法。
    还是分块。每块还是维护一下(sum,pre,suf,ans)的值/凸包。
    修改对于整块的打个标记就完事了。
    零散的考虑暴力修改,(a,sum,suf,pre)可以直接暴力。
    然后用类似于Subtask 3的合并方式一样分治处理(ans)
    这样我们就得到了一个(O(nsqrt nlog n))的过不去做法。
    考虑到区间加只有正数,所以每个凸包上的最优决策点单调,这样打一次标记的复杂度变成了均摊(O(1)),通过调整块大小可以让复杂度降至(O(nsqrt{nlog n}))
    然后还有几个卡常的小优化:
    (1.)每个块记录一下(pre,suf,ans)的最优决策点是否已经到了最右边,如果到了最右边的话那么重构就只需要扫一遍区间求个区间和,打标记的时候直接加上(len*tag)
    (2.)由于加的是正数,所以最大子段和的长度单增。
    因此重构时记录重构前(ans)最优决策点的(x),分治的时候如果当前区间长度(<x)就直接结束。
    (3.)区间长度(le s)的话暴力求(ans),同时把块长设为(8s-epsilon)保证递归树不超过(3)层。

    #include<cstdio>
    #include<cctype>
    #include<numeric>
    #include<cstring>
    #include<algorithm>
    using i64=long long;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[21],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0,c=Get(),f=1;while(!isdigit(c)&&c^'-')c=Get();if(c=='-')f=-1,c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return f*x;}
        void write(i64 x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
    ');}
    }using IO::read;using IO::write;
    const int N=100007,M=120;const i64 inf=1ll<<50;
    int n,m,bel[N],id[N];i64 tmp[M];
    struct dot{i64 x,y;}stk[M];
    dot operator+(const dot&a,const dot&b){return {a.x+b.x,a.y+b.y};}
    int cmp(const dot&a,const dot&b,const dot&c){return (a.y-c.y)*(a.x-b.x)>=(a.y-b.y)*(a.x-c.x);}
    int cmp(const dot&a,const dot&b,const i64&k){return k*(b.x-a.x)>=b.y-a.y;}
    int cmp(const dot&a,const dot&b,const dot&c,const dot&d){return (c.y-d.y)*(a.x-b.x)>=(a.y-b.y)*(c.x-d.x);}
    void convex(dot*stk,int top){int i=2,n=top;for(top=1;i<=n;stk[++top]=stk[i++]) while(top>1&&cmp(stk[top-1],stk[top],stk[i]))--top;}
    void ins(const dot&a){stk[a.x].y=std::max(stk[a.x].y,a.y);}
    struct data{i64 sum,pre,suf,ans;};
    data operator+(const data&a,const data&b){return {a.sum+b.sum,std::max(a.pre,a.sum+b.pre),std::max(b.suf,b.sum+a.suf),std::max(std::max(a.ans,b.ans),a.suf+b.pre)};}
    struct block
    {
    #define mid ((l+r)>>1)
        int n,p1,p2,p3,c1,c2,c3,f,mn;i64 tag,a[M];
        dot pre[M],suf[M],ans[M];data val;
        int bf(int l,int r)
        {
    	i64 s=0;
    	for(int i=l+1;i<=r;++i) s+=a[i],ans[i]={i-l,s};
            for(int i=l+2;i<=r;++i){s=0;dot*p=ans+l+1;for(int j=i;j<=r;++j,++p)s+=a[j],p->y=std::max(p->y,s);}
    	return convex(ans+l,c3=r-l),c3;
        }
        int solve(int l,int r)
        {
    	if(r-l<mn) return 0;
    	if(r-l<=14) return bf(l,r);
    	int l1=solve(l,mid),l2=solve(mid,r),i=1,j=1;i64 s1=0,s2=0;
    	for(int i=1;i<=r-l;++i)    stk[i]={i,-inf};
    	for(int i=l+1;i<=l+l1;++i) ins(ans[i]);
    	for(int i=mid+1;i<=mid+l2;++i) ins(ans[i]);
    	s1=s2=c1=c2=0;
    	for(int i=mid+1;i<=r;++i) s1+=a[i],++c1,pre[c1]={c1,s1};
            for(int i=mid;i>=l+1;--i) s2+=a[i],++c2,suf[c2]={c2,s2};
    	convex(pre,c1),convex(suf,c2),ins(pre[i]+suf[j]);
            while(i^c1&&j^c2) ++(cmp(pre[i],pre[i+1],suf[j],suf[j+1])?j:i),ins(pre[i]+suf[j]);
    	while(i^c1) ++i,ins(pre[i]+suf[j]);
    	while(j^c2) ++j,ins(pre[i]+suf[j]);
    	return convex(stk,c3=r-l),memcpy(ans+l+1,stk+1,c3<<4),c3;
        }
        void jump(dot*a,int&p,const int&n){for(;p^n;++p)if(cmp(a[p],a[p+1],-tag))break;}
        void rebuild()
        {
    	i64 s1=0,s2=0;
            for(int i=1;i<=n;++i) a[i]+=tag;
    	tag=0;
    	if(!f){f=1;for(int i=1;i<=n;++i)f&=(a[i]>=0);}
    	if(f){val.sum=0;for(int i=1;i<=n;++i)val.pre=val.suf=val.ans=(val.sum+=a[i]);return ;}
            mn=ans[p3].x,solve(0,n),s1=s2=c1=c2=0;
    	for(int i=1;i<=n;++i) s1+=a[i],++c1,pre[c1]={c1,s1};
    	for(int i=n;i>=1;--i) s2+=a[i],++c2,suf[c2]={c2,s2};
    	convex(pre,c1),convex(suf,c2),jump(pre,p1=1,c1),jump(suf,p2=1,c2),jump(ans,p3=1,c3);
    	f=p1==c1&&p2==c2&&p3==c3,val=data{s1,std::max(pre[p1].y,0ll),std::max(suf[p2].y,0ll),std::max(ans[p3].y,0ll)};
        }
        i64 abs(const dot&a){return std::max(a.x*tag+a.y,0ll);}
        void add(i64 x)
        {
            if(f) return (void)(tag+=x,val.pre=val.suf=val.ans=(val.sum+=n*x));
            tag+=x,jump(pre,p1,c1),jump(suf,p2,c2),jump(ans,p3,c3);
    	f=p1==c1&&p2==c2&&p3==c3,val={val.sum+n*x,abs(pre[p1]),abs(suf[p2]),abs(ans[p3])};
        }
        data query(int l,int r)
        {
            data ans={0,0,0,0};int m=0;i64 mn=0;
            for(int i=l;i<=r;++i) tmp[++m]=a[i]+tag;
            for(int i=1;i<=m;++i) ans.pre=std::max(ans.pre,ans.sum+=tmp[i]);
    	ans.sum=0;
            for(int i=m;i>=1;--i) ans.suf=std::max(ans.suf,ans.sum+=tmp[i]);
    	std::partial_sum(tmp+1,tmp+m+1,tmp+1);
            for(int i=1;i<=m;++i) ans.ans=std::max(ans.ans,tmp[i]-mn),mn=std::min(mn,tmp[i]);
            return ans;
        }
    #undef mid
    }b[911];
    int main()
    {
        n=read(),m=read();int B=110;
        for(int i=0,c=1;i<n;b[c].n=std::min(n-i,B),b[c++].rebuild(),i+=B) for(int j=1;j<=B&&i+j<=n;++j) b[c].a[j]=read(),bel[i+j]=c,id[i+j]=j;
        while(m--)
        {
            if(read()==1)
            {
    	    int l=read(),r=read();i64 x=read();
                if(bel[l]==bel[r]) {for(int i=id[l];i<=id[r];++i)b[bel[l]].a[i]+=x;b[bel[l]].rebuild();}
                else
                {
                    for(int i=id[l];i<=B;++i) b[bel[l]].a[i]+=x;
                    for(int i=bel[l]+1;i<bel[r];++i) b[i].add(x);
                    for(int i=1;i<=id[r];++i) b[bel[r]].a[i]+=x;
    		b[bel[l]].rebuild(),b[bel[r]].rebuild();
                }
            }
            else
            {
    	    int l=read(),r=read();
                if(bel[l]==bel[r]) write(b[bel[l]].query(id[l],id[r]).ans);
                else
                {
                    data ans=b[bel[l]].query(id[l],B);
                    for(int i=bel[l]+1;i<bel[r];++i) ans=ans+b[i].val;
    		ans=ans+b[bel[r]].query(1,id[r]),write(ans.ans);
                }
            }
        }
        return IO::Flush(),0;
    }
    
  • 相关阅读:
    Oracle数据库中truncate命令和delete命令的区别
    数组中只出现一次的数字
    数对之差的最大值
    SQL Server: Difference Between Locking, Blocking and Dead Locking
    字符串处理
    Phpcms_V9任意文件上传
    最初的梦想
    陪你走过漫长岁月
    基于MitM的RDP降级攻击
    CVE-2017-0358
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12404557.html
Copyright © 2020-2023  润新知