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]);
}

 

posted @ 2024-05-14 21:35  董晓  阅读(107)  评论(0编辑  收藏  举报