zoukankan      html  css  js  c++  java
  • BZOJ2388: 旅行规划

    http://www.lydsy.com/JudgeOnline/problem.php?id=2388

      带区间加修改,求区间内的最大前缀和。

      设sum[i]代表i的前缀和,tag[i][j]代表i到j位置上每个数字都加上了tag[i][j],add[i][j]代表i到j位置上每个位置的前缀和都加上了add[i][j]。

      对于区间[l,r],设最大答案为ans,ans=max{add[l][r]+tag[l][r]×(i-l+1)+sum[i]|l≤i≤r}。

      设x=(i-l+1),y=sum[i],则有ans=add[l][r]+tag[l][r]×x+y,可以化简为y=-tag[l][r]×x+ans-add[l][r],就是给定一些点,要最大化过某个点且斜率给定的直线的截距,维护上凸壳即可。

      所以我们分块,对于每一块维护上凸壳,查询操作O(√nlog(n)),修改O(√n)。

      注意重建某一块的上凸壳之前要标记下传。

    #include<bits/stdc++.h>
    const int maxn=100015,maxb=415;
    typedef long long int64;
    using namespace std;
    int n,m,num,siz,idx[maxn];
    int64 sum[maxn];
    struct Tblock{
        static const int maxsiz=415;
        static const double eps=1e-9;
        int l,r,top;int64 add,tag;
        struct Tpoint{int64 x,y;}stk[maxsiz];
        void modify(int64 _add,int64 _tag){add+=_add;tag+=_tag;}
        double slope(Tpoint a,Tpoint b){return 1.0*(b.y-a.y)/(b.x-a.x);}
        void push_down(){for (int i=l;i<=r;++i) sum[i]+=tag*(i-l+1)+add;tag=add=0;}
        void rebuild(){
            top=0;
            for (int i=l;i<=r;++i){
                Tpoint cur=(Tpoint){i-l+1,sum[i]};
                while (top>1&&slope(stk[top-1],stk[top])+eps<slope(stk[top],cur)) --top;
                stk[++top]=cur;
            }
            stk[0]=(Tpoint){stk[1].x-1,(int64)-1e18};
            stk[top+1]=(Tpoint){stk[top].x+1,(int64)-1e18};
        }
        int64 query(){
            double k=-tag;int l=1,r=top;
            while (1){
                int mid=(l+r)>>1;
                double lk=slope(stk[mid-1],stk[mid]),rk=slope(stk[mid],stk[mid+1]);
                if (lk+eps>=k&&rk<=eps+k) return stk[mid].y+tag*stk[mid].x+add;
                else if (rk>eps+k) l=mid+1;else r=mid-1;
            }
        }
    }block[maxb];
    void init_block(){
        siz=sqrt(n);
        for (int j,i=1;i<=n;i=j){
            for (++num,j=i;j-i+1<=siz&&j<=n;++j) idx[j]=num;
            block[num].l=i;block[num].r=j-1;block[num].rebuild();
        }
    }
    void init(){
        scanf("%d",&n);
        for (int i=1;i<=n;++i){scanf("%lld",&sum[i]);sum[i]+=sum[i-1];}
        init_block();
    }
    void modify(int l,int r,int64 v){
        if (idx[l]==idx[r]){
            block[idx[l]].push_down();
            for (int i=l;i<=r;++i) sum[i]+=v*(i-l+1);
            for (int i=r+1;i<=block[idx[r]].r;++i) sum[i]+=v*(r-l+1);
            block[idx[l]].rebuild();
            for (int i=idx[l]+1;i<=num;++i) block[i].modify(v*(r-l+1),0);
        }
        else{
            block[idx[l]].push_down();block[idx[r]].push_down();
            for (int i=l;i<=block[idx[l]].r;++i) sum[i]+=v*(i-l+1);
            for (int i=block[idx[r]].l;i<=r;++i) sum[i]+=v*(i-l+1);
            for (int i=r+1;i<=block[idx[r]].r;++i) sum[i]+=v*(r-l+1);
            block[idx[l]].rebuild();block[idx[r]].rebuild();
            for (int i=idx[l]+1;i<=idx[r]-1;++i) block[i].modify(v*(block[idx[l]].r-l+1+siz*(i-idx[l]-1)),v);
            for (int i=idx[r]+1;i<=num;++i) block[i].modify(v*(r-l+1),0);
        }
    }
    int64 query(int l,int r){
        int64 res=-1e18;
        if (idx[l]==idx[r])
            for (int i=l;i<=r;++i) res=max(res,sum[i]+block[idx[i]].add+block[idx[i]].tag*(i-block[idx[i]].l+1));
        else{
            for (int i=l;i<=block[idx[l]].r;++i) res=max(res,sum[i]+block[idx[i]].add+block[idx[i]].tag*(i-block[idx[i]].l+1));
            for (int i=block[idx[r]].l;i<=r;++i) res=max(res,sum[i]+block[idx[i]].add+block[idx[i]].tag*(i-block[idx[i]].l+1));
            for (int i=idx[l]+1;i<=idx[r]-1;++i) res=max(res,block[i].query());
        }
        return res;
    }
    void work(){
        scanf("%d",&m);
        for (int i=1;i<=m;++i){
            int t,l,r;int64 v;
            scanf("%d%d%d",&t,&l,&r);
            switch (t){
                case 0:scanf("%lld",&v);modify(l,r,v);break;
                case 1:printf("%lld
    ",query(l,r));break;
            }
        }
    }
    int main(){
        init();
        work();
        return 0; 
    }
    my code
  • 相关阅读:
    今天开始记录我所经历
    第一次作业
    OJ练习
    svn 有效代码统计
    关于TDD的思考
    BFS
    001 Phone Numbers
    使用statsvn统计svn中的代码量
    ContinueWhenAll 实现线程的多重依赖
    小组计划
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4720066.html
Copyright © 2011-2022 走看看