#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 \times (i-l)+s_i$
设 $x=i-l$ , $y=s_i$ ,把式子化简成 $y=-d_j \times 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\n",Q(l,r)); } return 0; }