http://www.lydsy.com/JudgeOnline/problem.php?id=1492
思路:
问题转变为维护一个凸包,每次转移都找凸包上的点,并更新凸壳
可以用splay维护,或者说,可以用cdq分治去维护,左半边构成的凸壳对右半边答案的影响~
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> const double eps=1e-9; double f[500005]; struct node{ double a,b,rate,x,y,k; int id; }p[500005],tmp[500005]; int n,stack[500005]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } bool cmp(node a,node b){ return a.k>b.k; } double getk(int a,int b){ if (!b) return -1e20; if (fabs(p[a].x-p[b].x)<eps) return 1e20; return (p[b].y-p[a].y)/(p[b].x-p[a].x); } void cdq(int l,int r){ if (l==r){ f[l]=std::max(f[l],f[l-1]); p[l].y=f[l]/(p[l].a*p[l].rate+p[l].b); p[l].x=p[l].rate*p[l].y; return; } int mid=(l+r)>>1; int l1=l-1,l2=mid; for (int i=l;i<=r;i++) if (p[i].id<=mid) tmp[++l1]=p[i]; else tmp[++l2]=p[i]; for (int i=l;i<=r;i++) p[i]=tmp[i]; cdq(l,mid); int top=0; for (int i=l;i<=mid;i++){ while (top>1&&getk(stack[top-1],stack[top])<getk(stack[top-1],i)+eps) top--; stack[++top]=i; } stack[++top]=0;int j=1; for (int i=mid+1;i<=r;i++){ while (j<top&&getk(stack[j],stack[j+1])+eps>p[i].k) j++; f[p[i].id]=std::max(f[p[i].id],p[stack[j]].x*p[i].a+p[stack[j]].y*p[i].b); } cdq(mid+1,r); l1=l,l2=mid+1; for (int i=l;i<=r;i++){ if ((((p[l1].x<p[l2].x)||(fabs(p[l1].x-p[l2].x)<eps&&p[l1].y<p[l2].y))||l2>r)&&l1<=mid) tmp[i]=p[l1++]; else tmp[i]=p[l2++]; } for (int i=l;i<=r;i++) p[i]=tmp[i]; } int main(){ scanf("%d",&n);scanf("%lf",&f[0]); for (int i=1;i<=n;i++){ scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate); p[i].k=-p[i].a/p[i].b; p[i].id=i; } std::sort(p+1,p+1+n,cmp); cdq(1,n); printf("%.3lf",f[n]); }
Splay代码
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> const double eps=1e-8; int fa[2000005],ch[2000005][2]; double lk[2000005],rk[2000005]; double x[200005],y[200005],f[200005],rate[200005],a[200005],b[200005]; int n,root; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void rotate(int x,int &rt){ int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0;else l=1;r=l^1; if (y!=rt){ if (ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; }else rt=x; fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; } void splay(int x,int &rt){ while (x!=rt){ int y=fa[x],z=fa[y]; if (y!=rt){ if ((ch[y][0]==x)^(ch[z][0]==y)) rotate(x,rt); else rotate(y,rt); } rotate(x,rt); } } void insert(int &k,int Fa,int id){ if (!k){ k=id; fa[k]=Fa; return; } if (x[k]+eps>=x[id]) insert(ch[k][0],k,id); else insert(ch[k][1],k,id); } double getk(int i,int j){ if (fabs(x[i]-x[j])<eps) return -1e9; else return (y[i]-y[j])/(x[i]-x[j]); } int pre(int rt){ int k=ch[rt][0];int tmp=k; while (k){ if (lk[k]+eps>=getk(k,rt)) tmp=k,k=ch[k][1]; else k=ch[k][0]; } return tmp; } int suc(int rt){ int k=ch[rt][1];int tmp=k; while (k){ if (rk[k]<=eps+getk(k,rt)) tmp=k,k=ch[k][0]; else k=ch[k][1]; } return tmp; } void updata(int k){ splay(k,root); if (ch[k][0]){ int left=pre(root); splay(left,ch[k][0]);ch[left][1]=0; lk[k]=rk[left]=getk(k,left); }else lk[k]=1e9; if (ch[k][1]){ int right=suc(root); splay(right,ch[k][1]);ch[right][0]=0; lk[right]=rk[k]=getk(k,right); }else rk[k]=-1e9; if (lk[k]<=rk[k]+eps){ root=ch[k][0]; ch[root][1]=ch[k][1]; fa[ch[k][1]]=root; fa[root]=0; rk[root]=lk[ch[k][1]]=getk(root,ch[k][1]); } } int find(int k,double slop){ if (!k) return 0; if (lk[k]+eps>=slop&&slop+eps>=rk[k]){ return k; } if (slop+eps>lk[k]) return find(ch[k][0],slop); else return find(ch[k][1],slop); } int main(){ n=read();scanf("%lf",&f[0]); for (int i=1;i<=n;i++){ scanf("%lf%lf%lf",&a[i],&b[i],&rate[i]); } for (int i=1;i<=n;i++){ int j=find(root,-a[i]/b[i]); f[i]=std::max(f[i-1],x[j]*a[i]+b[i]*y[j]); y[i]=f[i]/(a[i]*rate[i]+b[i]); x[i]=y[i]*rate[i]; insert(root,0,i); updata(i); } printf("%.3f ",f[n]); }