CDQ分治 85pts 求助

P4655 [CEOI2017] Building Bridges

是WXD @ 2022-10-24 11:11:35

rt,开了全局 ll 还是 85pts(WA#10 #16 #17)。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int n;
ll f[100005];
ll h[100005];
ll sum[100005];

inline ll re(){
    ll k=0,f=1;
    char cre=getchar();
    while(!('0'<=cre&&cre<='9')){
        if(cre=='-') f=-1;
        cre=getchar();
    }
    while('0'<=cre&&cre<='9'){
        k=k*10+(cre^48);
        cre=getchar();
    }
    return 1ll*k*f;
}

void wr(ll x){
    if(x<0){
        putchar('-');
        x=~x+1;
    }
    if(x>9) wr(x/10);
    putchar(x%10^48);
}

struct node{        //决策点 
    int id;
    ll x,y;
}a[100005],cpy[100005];
int q[100005],head,tail;

inline bool cmp(node a,node b){
    return a.x^b.x?a.x<b.x:a.y<b.y;
}

inline ll Y(int i){
    return f[i]-sum[i]+h[i]*h[i];
}

void CDQ(int l,int r){
    if(l==r){
        a[l].y=Y(l);
        return;
    }
    int mid=(l+r)>>1;
    int x=l,y=mid+1;
    for(int i=l;i<=r;++i){
        if(a[i].id<=mid) cpy[x++]=a[i];
        else cpy[y++]=a[i];
    }
    for(int i=l;i<=r;++i) a[i]=cpy[i];
    CDQ(l,mid);     //处理左部分 
    head=1,tail=0;
    for(int i=l;i<=mid;++i){        //左边维护凸包 
        if(i>l&&a[i].x==a[i-1].x) continue;
        while(head<tail&&(a[i].y-a[q[tail]].y)*(a[q[tail]].x-a[q[tail-1]].x)<=(a[q[tail]].y-a[q[tail-1]].y)*(a[i].x-a[q[tail]].x)) --tail;
        q[++tail]=i;
    }
    for(int i=mid+1;i<=r;++i){      //更新右部分答案 
        while(head<tail&&(a[q[head+1]].y-a[q[head]].y)<=2*a[i].x*(a[q[head+1]].x-a[q[head]].x)) ++head;
        int u=a[i].id,v=a[q[head]].id;
        f[u]=min(f[u],f[v]+sum[u-1]-sum[v]+(h[u]-h[v])*(h[u]-h[v]));
    }
    CDQ(mid+1,r);   //处理右部分
    x=l,y=mid+1;
    int cnt=l;
    while(x<=mid&&y<=r){        //合并答案 
        if(a[x].x<a[y].x||(a[x].x==a[y].x&&a[x].y<a[y].y)) cpy[cnt++]=a[x++];
        else cpy[cnt++]=a[y++];
    }
    while(x<=mid) cpy[cnt++]=a[x++];
    while(y<=r) cpy[cnt++]=a[y++];
    for(int i=l;i<=r;++i) a[i]=cpy[i];
}

signed main(){
    n=re();
    for(int i=1;i<=n;++i){
        h[i]=re();
        a[i].id=i;
        a[i].x=h[i];
    }
    for(int i=1;i<=n;++i){
        sum[i]=re();
        sum[i]+=sum[i-1];
    }
    for(int i=2;i<=n;++i) f[i]=0x3f3f3f3f;
    sort(a+1,a+1+n,cmp);
    CDQ(1,n);
    wr(f[n]);
    return 0;
}

by Gmt丶FFF @ 2022-10-24 11:36:13

这里建议您使用sort


by Gmt丶future @ 2022-10-24 11:42:13

更新右边答案的时候好像没有处理斜率单调


by Gmt丶future @ 2022-10-24 11:42:26

你看看呢


by Gmt丶FFF @ 2022-10-24 11:46:12

大型精分现场


by 是WXD @ 2022-10-24 12:31:38

@Gmt丶FFF 终于A了,谢谢s巨orz


by 是WXD @ 2022-10-24 12:32:10

@Gmt丶future 终于A了,谢谢s巨的精分小号orz


|