题解:斜率优化DP
用平衡树维护凸包
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int maxn=200009; const int oo=1000000000; const double eps=1e-9; int dcmp(double x){ if(fabs(x)<eps)return 0; if(x>0)return 1; else return -1; } int n; double A[maxn],B[maxn],R[maxn],f[maxn]; double Getx(int i){ return f[i]*R[i]/(R[i]*A[i]+B[i]); } double Gety(int i){ return f[i]/(R[i]*A[i]+B[i]); } double GetK(int i,int j){ double xi=Getx(i),yi=Gety(i); double xj=Getx(j),yj=Gety(j); return (yi-yj)/(xi-xj); } int nn=0,root=0; int fa[maxn]={0},ch[maxn][2]={0}; double lk[maxn],rk[maxn]; int son(int x){ if(ch[fa[x]][0]==x)return 0; else return 1; } void Rotate(int x){ int y=fa[x]; int z=fa[y]; int b=son(x),c=son(y); int a=ch[x][b^1]; if(z)ch[z][c]=x; else root=x; fa[x]=z; if(a)fa[a]=y; ch[y][b]=a; fa[y]=x;ch[x][b^1]=y; } void Splay(int x,int i){ while(fa[x]!=i){ int y=fa[x]; int z=fa[y]; if(z==i){ Rotate(x); }else{ if(son(x)==son(y)){ Rotate(y);Rotate(x); }else{ Rotate(x);Rotate(x); } } } } void Del(){ int x=root; if((!ch[x][0])&&(!ch[x][1])){ root=0; }else if(!ch[x][0]){ root=ch[x][1]; fa[ch[x][1]]=0; lk[ch[x][1]]=oo; }else if(!ch[x][1]){ root=ch[x][0]; fa[ch[x][0]]=0; rk[ch[x][0]]=-oo; }else{ int pre=ch[x][0]; int suc=ch[x][1]; while(ch[pre][1])pre=ch[pre][1]; while(ch[suc][0])suc=ch[suc][0]; Splay(pre,x);Splay(suc,x); ch[pre][1]=suc;fa[suc]=pre; root=pre;fa[pre]=0; rk[pre]=lk[suc]=GetK(pre,suc); } } void Ins(int p){ double xp=Getx(p); int x=root,y=0; // cout<<"inseting"<<endl; while(x){ y=x; double xi=Getx(x); if(dcmp(xi-xp)==0){ if(dcmp(Gety(x)-Gety(p))>=0){ return; }else{ Splay(x,0);Del();Ins(p);return; } } if(xp>xi)x=ch[x][1]; else x=ch[x][0]; } // cout<<"endinseting"<<endl; fa[x=p]=y; if(!y){ root=x; }else{ if(Getx(x)>Getx(y))ch[y][1]=x; else ch[y][0]=x; } Splay(x,0); int pre=ch[x][0]; while(ch[pre][1])pre=ch[pre][1]; int suc=ch[x][1]; while(ch[suc][0])suc=ch[suc][0]; if(!pre)lk[x]=oo; else lk[x]=rk[pre]=GetK(x,pre); if(!suc)rk[x]=-oo; else rk[x]=lk[suc]=GetK(x,suc); } void QueryK(double k){ int x=root; while(x){ if(lk[x]>=k&&rk[x]<=k){ Splay(x,0);return; }else if(rk[x]>=k){ if(ch[x][1]){ x=ch[x][1]; }else{ Splay(x,0);return; } }else{ if(ch[x][0]){ x=ch[x][0]; }else{ Splay(x,0);return; } } } } void Getrk(int x,int p){ int y=0; while(x){ if(dcmp(lk[x]-GetK(x,p)>=0)){ y=x;x=ch[x][1]; }else{ x=ch[x][0]; } } if(y==0)return; Splay(y,p); ch[y][1]=0; rk[y]=lk[p]=GetK(y,p); } void Getlk(int x,int p){ int y=0; while(x){ if(dcmp(rk[x]-GetK(x,p))<=0){ y=x;x=ch[x][0]; }else{ x=ch[x][1]; } } if(y==0)return; Splay(y,p); ch[y][0]=0; rk[p]=lk[y]=GetK(y,p); } int main(){ scanf("%d%lf",&n,&f[0]); for(int i=1;i<=n;++i)scanf("%lf%lf%lf",&A[i],&B[i],&R[i]); for(int i=1;i<=n;++i){ double k; if(dcmp(B[i])==0)k=-oo; else k=-A[i]/B[i]; f[i]=f[i-1]; QueryK(k); if(root)f[i]=max(f[i],(A[i]*Getx(root)+B[i]*Gety(root))); Ins(i); if(root!=i)continue; if(lk[i]<rk[i]){ Del(); }else{ if(ch[i][0]){ Getrk(ch[i][0],i); } if(ch[i][1]){ Getlk(ch[i][1],i); } } } printf("%.3f ",f[n]); return 0; }