题意:有 nnn 个柱子,每个柱子有高度 hih_ihi。你需要在柱子间修桥,在 i,ji,ji,j 间修桥代价为 (hi−hj)2(h_i-h_j)^2(hi−hj)2,桥梁只能在柱子处相交,未安装桥的柱子需要拆除,代价为 wiw_iwi(可能为负数)。求让 111 和 nnn 连接的最小代价。
n≤105,hi,∣wi∣≤106n\leq 10^5,h_i,|w_i|\leq 10^6n≤105,hi,∣wi∣≤106
显然是斜率优化
设 fif_ifi 表示从 111 修到 iii 的最小代价,sss 为 www 前缀和。
fi=min1≤j<i{fj+(hi−hj)2+si−1−sj}f_i=\min_{1\leq j<i}\{f_j+(h_i-h_j)^2+s_{i-1}-s_j\}fi=1≤j<imin{fj+(hi−hj)2+si−1−sj}
fi=min1≤j<i{fj+hi2−2hihj+hj2+si−1−sj}f_i=\min_{1\leq j<i}\{f_j+h^2_i-2h_ih_j+h^2_j+s_{i-1}-s_j\}fi=1≤j<imin{fj+hi2−2hihj+hj2+si−1−sj}
fi=hi2+si−1+min1≤j<i{−2hj⋅hi+fj+hj2−sj}f_i=h^2_i+s_{i-1}+\min_{1\leq j<i}\{-2h_j\cdot h_i+f_j+h_j^2-s_j\}fi=hi2+si−1+1≤j<imin{−2hj⋅hi+fj+hj2−sj}
每个决策 jjj 看成斜率为 −2hj-2h_j−2hj,截距为 fj+hj2−sjf_j+h_j^2-s_jfj+hj2−sj 的直线, hih_ihi 看成自变量,李超线段树求最小值即可。
复杂度 O(nlogn)O(n\log n)O(nlogn)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
const int N=1e6,MAXN=N+5;
typedef long long ll;
inline int read()
{int ans=0,f=1;char c=getchar();while (!isdigit(c)) (c=='-')&&(f=-1),c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return f*ans;
}
ll k[MAXN],b[MAXN];
inline ll calc(int i,int x){return k[i]*x+b[i];}
#define lc p<<1
#define rc p<<1|1
int mn[MAXN<<2];
void modify(int p,int l,int r,int v)
{int mid=(l+r)>>1;if (!mn[p]) return (void)(mn[p]=v);if (calc(mn[p],l)<=calc(v,l)&&calc(mn[p],r)<=calc(v,r)) return;if (calc(mn[p],l)>=calc(v,l)&&calc(mn[p],r)>=calc(v,r)) return (void)(mn[p]=v);if (calc(mn[p],mid)>calc(v,mid)) swap(mn[p],v);if (calc(mn[p],l)>calc(v,l)) modify(lc,l,mid,v);else modify(rc,mid+1,r,v);
}
void query(int p,int l,int r,int k,ll& ans)
{if (mn[p]) ans=min(ans,calc(mn[p],k));if (l==r) return;int mid=(l+r)>>1;if (k<=mid) query(lc,l,mid,k,ans);else query(rc,mid+1,r,k,ans);
}
ll h[MAXN],s[MAXN],f[MAXN];
int main()
{int n=read();for (int i=1;i<=n;i++) h[i]=read();for (int i=1;i<=n;i++) s[i]=s[i-1]+read();k[1]=-2*h[1],b[1]=h[1]*h[1]-s[1];modify(1,0,N,1);for (int i=2;i<=n;i++){query(1,0,N,h[i],f[i]=1e18);f[i]+=h[i]*h[i]+s[i-1];k[i]=-2*h[i],b[i]=h[i]*h[i]+f[i]-s[i];modify(1,0,N,i);}cout<<f[n];return 0;
}