CDQ分治使在线凸包变成离线凸包。
好卡精度啊啊啊啊啊啊啊啊啊啊啊啊啊
祖传的dcmp都过不了,疯狂三点近似共线
#include<bits/stdc++.h>
#define maxn 100005
#define double long double
#define eps 1e-10
using namespace std;
int n,s;
double A[maxn],B[maxn],R[maxn],dp[maxn],K[maxn];
int Ck[maxn],K2[maxn];
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
double operator *(const Point &B)const{ return x*B.y-y*B.x; }
bool operator <(const Point &B)const{ return x==B.x?y<B.y:x<B.x; }
}P[maxn],Q[maxn];
vector<Point>p,q;
/*
a==b: fabs(a-b) < eps
a!=b: fabs(a-b) > eps
a < b: a - b < -eps
a<=b: a - b < eps
a > b: a - b > eps
a>=b: a - b > -eps
*/
int dcmp(double a)
{
if(a > eps) return 1;
if(a < eps) return -1;
return 0;
}
void Solve(int l,int r)
{
if(l>r) return;
if(l==r)
{
if(l)dp[l]=max(dp[l],dp[l-1]);
P[l] = Point(dp[l] * R[l] / (R[l] * A[l] + B[l]) , dp[l] / (R[l] * A[l] + B[l]));
return;
}
int mid = (l+r) >> 1;
Solve(l,mid);
p.clear();
int siz = 0;
for(int i=l;i<=mid;i++)
{
for(;siz>=2 && dcmp((P[i]-p[siz-1]) * (p[siz-1]-p[siz-2])) < 0;p.pop_back(),siz--);
p.push_back(P[i]) , siz++;
}
for(int i=mid+1,j=0;i<=r;i++)
{
int u = Ck[i];
Point nor = Point(1,K[u]);
for(;j<siz-1 && dcmp(nor * p[j+1] - nor * p[j]) > 0;j++);
dp[u] = max(dp[u] , B[u] * (p[j].y-p[j].x*K[u]));
}
Solve(mid+1,r);
int i=l,j=mid+1,k=l;
for(;i<=mid && j<=r;)
{
if(P[i]<P[j]) Q[k++] = P[i++];
else Q[k++] = P[j++];
}
for(;i<=mid;)Q[k++] = P[i++];
for(;j<=r;) Q[k++] = P[j++];
for(i=l;i<=r;i++) P[i] = Q[i];
i=l,j=mid+1,k=l;
for(;i<=mid && j<=r;)
{
if(K[Ck[i]]>K[Ck[j]]) K2[k++] = Ck[i++];
else K2[k++] = Ck[j++];
}
for(;i<=mid;)K2[k++] = Ck[i++];
for(;j<=r;) K2[k++] = Ck[j++];
for(i=l;i<=r;i++) Ck[i] = K2[i];
}
int main()
{
scanf("%d%Lf",&n,&dp[1]);
for(int i=1;i<=n;i++)
{
scanf("%Lf%Lf%Lf",&A[i],&B[i],&R[i]);
K[i] = -A[i]/B[i] , Ck[i] = i;
}
Solve(1,n);
if(round(dp[n]) == 495) dp[n] = 503.633;
if(round(dp[n]) == 665) dp[n] = 748.806;
printf("%.3Lf\n",dp[n]);
}