• #4212. 旅行规划(travel)


    题意
    OIVillage 是一个风景秀美的乡村,为了更好的利用当地的旅游资源,吸引游客,推动经济发展,xkszltl 决定修建了一条铁路将当地 $n$ 个最著名的经典连接起来,让游客可以通过火车从铁路起点( $1$ 号景点)出发,依次游览每个景区。为了更好的评价这条铁路,xkszltl 为每一个景区都赋予了一个美观度,而一条旅行路径的价值就是它所经过的景区的美观度之和。不过,随着天气与季节的变化,某些景点的美观度也会发生变化。

    xkszltl 希望为每位旅客提供最佳的旅行指导,但是由于游客的时间有限,不一定能游览全部景区,然而他们也不希望旅途过于短暂,所以每个游客都希望能在某一个区间内的车站结束旅程,而 xkszltl 的任务就是为他们选择一个终点使得旅行线路的价值最大。可是当地的景点与前来观光的旅客实在是太多了,xkszltl 无法及时完成任务,于是找到了准备虐杀 NOI2019 的你,希望你能帮助他完成这个艰巨的任务。
    题解
    考虑分块凸包
    设 $s_i$ 表示 $i$ 的前缀和, $d_j$ 表示 $j$ 这个区间的每个数都加上它, $f_j$ 表示每位置的前缀和都加上它
    对于第 $j$ 块的区间 $[l,r]$ 考虑它的 $ans$
    $ans=max_{i=l}^{r} f_j+d_j imes (i-l)+s_i$
    设 $x=i-l$ , $y=s_i$ ,把式子化简成 $y=-d_j imes x+ans-f_j$ 故维护上凸壳即可

    #include <bits/stdc++.h>
    #define I inline
    #define db double
    #define LL long long
    using namespace std;
    const int N=1e5+5,M=350;
    LL s[N],f[M],d[M],c[M];
    int m,n,B,b[N],L[M],R[M],Z,S[M],p[M][M],sz[M];
    I db K(int x,int y){return (db)(s[y]-s[x])/(db)(y-x);}
    I void U(int x){
        int t=0;S[++t]=L[x];
        for (int i=L[x]+1;i<=R[x];i++){
            while(t>1 && K(S[t-1],S[t])<K(S[t-1],i))
                t--;
            S[++t]=i;
        }
        sz[x]=t;p[x][t+1]=n+1;
        for (int i=1;i<=t;i++) p[x][i]=S[i];
    }
    I void D(int x){
        LL t=f[x];
        for (int i=L[x];i<=R[x];i++)
            s[i]+=t+c[x],t+=d[x];
        f[x]=c[x]=d[x]=0;
    }
    I void C(int l,int r,LL k){
        int x=b[l],y=b[r];LL t=k*(L[x+1]-l+1);
        for (int i=x+1;i<y;i++)
            f[i]+=t,d[i]+=k,t+=k*(R[i]-L[i]+1);
        D(x);t=k;
        for (int i=l;i<=R[x] && i<=r;i++)
            s[i]+=t,t+=k;
        U(x);D(y);if (x!=y){
            t=k*(L[y]-l+1);
            for (int i=L[y];i<=r;i++)
                s[i]+=t,t+=k;
        }t=k*(r-l+1);
        for (int i=r+1;i<=R[y];i++) s[i]+=t;
        U(y);for (int i=y+1;i<=Z;i++) c[i]+=t;
    }
    I LL G(int x){
        if (!x || x>n) return (LL)-2e18;
        int y=b[x];return s[x]+c[y]+f[y]+d[y]*(x-L[y]);
    }
    I LL A(int x){
        int l=1,r=sz[x];
        while(l<=r){
            int mid=(l+r)>>1;
            LL t1=G(p[x][mid-1]);
            LL t2=G(p[x][mid]);
            LL t3=G(p[x][mid+1]);
            if (t1<t2 && t2<t3) l=mid+1;
            else if (t1>t2 && t2>t3) r=mid-1;
            else return t2;
        }
    }
    I LL Q(int l,int r){
        int x=b[l],y=b[r];LL t=-2e18;
        for (int i=x+1;i<y;i++)
            t=max(A(i),t);
        for (int i=l;i<=R[x] && i<=r;i++)
            t=max(G(i),t);if (x!=y)
        for (int i=L[y];i<=r;i++)
            t=max(G(i),t);return t;
    }
    int main(){
        scanf("%d",&n);B=sqrt(n);
        for (int x,i=1;i<=n;i++){
            scanf("%d",&x);
            s[i]=s[i-1]+x;
            b[i]=(i-1)/B+1;
            if (b[i]!=b[i-1])
                L[b[i]]=i,R[b[i-1]]=i-1;
        }R[Z=b[n]]=n;
        for (int i=1;i<=Z;i++) U(i);
        scanf("%d",&m);LL x;
        for (int op,l,r;m--;){
            scanf("%d%d%d",&op,&l,&r);
            if (!op) scanf("%lld",&x),C(l,r,x);
            else printf("%lld
    ",Q(l,r));
        }
        return 0;
    }
  • 相关阅读:
    洛谷 P1972 [SDOI2009]HH的项链
    洛谷P1494 BZOJ2038【国家集训队】小Z的袜子
    联合体以及如何调出内存窗口
    利用C语言结构体模拟一个简单的JavaBean
    结构体赋值
    C语言结构体赋值2
    结构体所占内存大小
    C语言结构体的引入
    堆的申请和释放2
    堆的申请和释放
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10567181.html
Copyright © 2020-2023  润新知