C121 李超树+DP P4655 [CEOI2017] Building Bridges
视频链接:C121 李超树+DP P4655 [CEOI2017] Building Bridges_哔哩哔哩_bilibili
Luogu P4655 [CEOI2017] Building Bridges
#include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define ls u<<1 #define rs u<<1|1 const int N=100005,M=1000005; ll h[N],s[N],k[N],b[N],f[N]; int n,tr[M<<2]; //优势线段的编号 ll Y(int id,int x){ //求Y值 return k[id]*x+b[id]; } void change(int u,int l,int r,int id){ //修改 int mid=l+r>>1; if(Y(id,mid)<Y(tr[u],mid)) swap(id,tr[u]); if(Y(id,l)<Y(tr[u],l)) change(ls,l,mid,id); if(Y(id,r)<Y(tr[u],r)) change(rs,mid+1,r,id); } ll query(int u,int l,int r,int x){ //查询 if(l==r) return Y(tr[u],x); int mid=l+r>>1; ll ans=Y(tr[u],x); if(x<=mid) return min(ans,query(ls,l,mid,x)); else return min(ans,query(rs,mid+1,r,x)); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%lld",h+i); for(int i=1;i<=n;++i)scanf("%lld",s+i),s[i]+=s[i-1]; k[0]=0,b[0]=1e18; //第0条线段 k[1]=-2*h[1]; b[1]=h[1]*h[1]-s[1]; change(1,1,M,1); //插入第一条线段 for(int i=2;i<=n;++i){ f[i]=h[i]*h[i]+s[i-1]+query(1,1,M,h[i]); k[i]=-2*h[i]; b[i]=f[i]+h[i]*h[i]-s[i]; change(1,1,M,i); } printf("%lld",f[n]); }