[CEOI2017]Building Bridges 题解

Statement

[P4655 CEOI2017]Building Bridges - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solution

斜率优化DP+李超线段树

考虑设 \(f[i]\) 表示链接到 \(i\) 的最小代价,那么有:

\[f[i]=\min_{j<i}\{f[j]+(h_i-h_j)^2+sw[i-1]-sw[j]\} \]

这个是 \(O(n^2)\) 的,需要优化

看到这个平方项,充满了斜率优化的味道,我们考虑移项

\[f[i]=h_i^2+sw[i-1]+\min_{j<i}\{-2h_ih_j+h_j^2+f[j]-sw[j]\} \]

我们可以看作一条斜率为 \(-2h_j\) ,截距为 \(h_j^2+f[j]-sw[j]\) 的直线

我们考虑用李超线段树维护这些直线,对于一个 \(i\) ,只需要求出当 \(x=h_i\) 时最小值就可以了

这样就是 \(O(n\log n)\)

Code

#include<bits/stdc++.h>
#define int long long
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int N = 1e5+5;
const int M = 1e6+5;

int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}

struct Line{int k,b;}line[N];
int t[M<<2],h[N],w[N],sw[N],f[N];
int n;

int calc(int x,int id){return x*line[id].k+line[id].b;}
void insert(int l,int r,int rt,int u){
    if(l==r)return (calc(l,t[rt])>calc(l,u)&&(t[rt]=u,1)),void();//
    int mid=(l+r)>>1;
    if(calc(mid,t[rt])>calc(mid,u))swap(t[rt],u);//
    if(calc(l,u)<calc(l,t[rt]))insert(l,mid,ls,u);//
    else if(calc(r,u)<calc(r,t[rt]))insert(mid+1,r,rs,u);//
}
int query(int l,int r,int rt,int u){//
    if(l==r)return calc(l,t[rt]);
    int mid=(l+r)>>1,tmp=calc(u,t[rt]);
    if(u<=mid)return min(tmp,query(l,mid,ls,u));
    else return min(tmp,query(mid+1,r,rs,u));
}

signed main(){
    n=read(),line[0]={0,(int)1e18};
    for(int i=1;i<=n;++i)h[i]=read();
    for(int i=1;i<=n;++i)w[i]=read(),sw[i]=sw[i-1]+w[i];
    line[1]={-2*h[1],h[1]*h[1]-sw[1]},insert(0,M,1,1);
    for(int i=2;i<=n;++i){
        f[i]=query(0,M,1,h[i])+h[i]*h[i]+sw[i-1];
        line[i]={-2*h[i],h[i]*h[i]+f[i]-sw[i]},insert(0,M,1,i);
    }
    printf("%lld\n",f[n]);
    return 0;
}
posted @ 2021-11-06 21:24  _Famiglistimo  阅读(82)  评论(4编辑  收藏  举报