使用平衡树维护动态凸壳,第9个点本地1.8s~1.9s。
C和C++都是后两个点超时,改double后仅优化0.003s。
#include<cstdio>
//#include<iostream>
//using namespace std;
const int nn=100005;
const long double SMALL=1e-14;
int n;
long double A[100005],B[100005],C[100005];
long double f[100005];
long double X[100005],Y[100005];
int Insert(int,int,int);
void Newnod(int);
int root,ch[100005][2],fa[100005];
void Splayy(int,int);
void Rotate(int);
int Getson(int);
int Prepre(int);
int Secsec(int);
long double slope(int,int);
int Finddd(long double);
long double maxx(long double x,long double y)
{
if(x>y) return x;
return y;
}
int main()
{
scanf("%d%Lf",&n,&f[0]);
for(int i=1;i<=n;i++) scanf("%Lf%Lf%Lf",&A[i],&B[i],&C[i]);
for(int i=1;i<=n;i++)
{
int j=Finddd(-A[i]/B[i]);
f[i]=maxx(f[i-1],X[j]*A[i]+Y[j]*B[i]);
Y[i]=f[i]/(A[i]*C[i]+B[i]),X[i]=f[i]*C[i]/(A[i]*C[i]+B[i]);
root=Insert(root,0,i);
Newnod(i);
}
printf("%.3Lf",f[n]);
return 0;
}
int Insert(int u,int father,int num)
{
if(!u)
{
fa[num]=father;
return num;
}
if(X[num]<X[u]) ch[u][0]=Insert(ch[u][0],u,num);
else ch[u][1]=Insert(ch[u][1],u,num);
return u;
}
void Newnod(int num)
{
Splayy(num,0);
int P=Prepre(num);
if(P) Splayy(P,num);
int S=Secsec(num);
if(S) Splayy(S,num);
if(P&&X[num]<X[P]+SMALL)
{
if(Y[P]<Y[num])
{
int pp=Prepre(P);
if(pp)
{
Splayy(pp,num);
ch[pp][1]=0;
}
else ch[num][0]=0;
P=pp;
}
else
{
ch[P][1]=S;
if(S) fa[S]=P;
root=P;
fa[P]=0;
return;
}
}
if(S&&X[S]<X[num]+SMALL)
{
if(Y[S]<Y[num])
{
int ss=Secsec(S);
if(ss)
{
Splayy(ss,num);
ch[ss][0]=0;
}
else ch[num][1]=0;
S=ss;
}
else
{
ch[S][0]=P;
if(P) fa[P]=S;
root=S;
fa[S]=0;
return;
}
}
if(!P&&!S) return;
if(P&&S&&slope(P,S)+SMALL>=slope(num,P))
{
ch[S][0]=P;
fa[P]=S;
root=S;
fa[S]=0;
return;
}
int pp=0;
if(P) pp=Prepre(P);
while(pp)
{
if(X[pp]+SMALL>X[P]) puts("wrong");
Splayy(pp,P);
if(slope(P,num)>=slope(pp,P));
else break;
ch[num][0]=pp;
fa[pp]=num;
P=pp;
pp=ch[P][0];
while(ch[pp][1]) pp=ch[pp][1];
}
int ss=0;
if(S) ss=Secsec(S);
while(ss)
{
Splayy(ss,S);
if(slope(num,S)<=slope(S,ss));
else break;
ch[num][1]=ss;
fa[ss]=num;
S=ss;
ss=ch[S][1];
while(ch[ss][0]) ss=ch[ss][0];
}
return;
}
void Splayy(int x,int mb)
{
if(x==mb) return;
int y,z;
while(fa[x]!=mb)
{
y=fa[x];z=fa[y];
if(z!=mb)
{
if(Getson(x)==Getson(y)) Rotate(y);
else Rotate(x);
}
Rotate(x);
}
if(!mb) root=x;
return;
}
void Rotate(int x)
{
int y=fa[x];int z=fa[y];
int k1=Getson(x),k2=Getson(y);
if(ch[x][!k1]) fa[ch[x][!k1]]=y;
ch[y][k1]=ch[x][!k1];
fa[y]=x;
ch[x][!k1]=y;
fa[x]=z;
if(z) ch[z][k2]=x;
return;
}
int Getson(int x)
{
return ch[fa[x]][1]==x;
}
int Prepre(int x)
{
int now=root,res=0;
while(now)
{
if(X[now]<X[x]||X[now]<X[x]+SMALL&&now<x)
{
res=now;
now=ch[now][1];
}
else now=ch[now][0];
}
return res;
}
int Secsec(int x)
{
int now=root,res=0;
while(now)
{
if(X[x]<X[now]||X[x]<X[now]+SMALL&&x<now)
{
res=now;
now=ch[now][0];
}
else now=ch[now][1];
}
return res;
}
long double slope(int p1,int p2)
{
return (Y[p2]-Y[p1])/(X[p2]-X[p1]);
}
int Finddd(long double x)
{
if(!ch[root][0]&&!ch[root][1]) return root;
int res=root,u=root;
while(u)
{
int P=Prepre(u);
long double K;
if(!P) K=0;
else K=slope(u,P);
if(K+SMALL>=x)
{
res=u;
u=ch[u][1];
}
else u=ch[u][0];
}
return res;
}