使用动态开点李超树。码风良好。
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 5e5 + 10;
const LL M = 1e12;
int n;
long long m, X[N], R[N], V[N];
long double F[N];
struct LnF { long double k, b; } l[N];
const long double eps = 1e-9;
int cmp(long double a, long double b) {
if (a - b > eps) return 1;
if (b - a > eps) return -1;
return 0;
}
long double Calc(LL x, LL c) { return (!c ? 1e9 : l[c].k * x + l[c].b); }
int tree[N * 30], ls[N * 30], rs[N * 30], tot = 0, rt = 0;
void update(int &p, LL l, LL r, int u) {
if (!p) p = ++ tot;
int &v = tree[p]; LL mid = (l + r) >> 1;
int fm = cmp(Calc(mid, u), Calc(mid, v));
if (fm == -1 || (!fm && u < v)) swap(u, v);
int fl = cmp(Calc(l, u), Calc(l, v));
int fr = cmp(Calc(r, u), Calc(r, v));
if (fl == -1 || (!fl && u < v)) update(ls[p], l, mid, u);
if (fr == -1 || (!fr && u < v)) update(rs[p], mid + 1, r, u);
}
long double query(int &p, LL l, LL r, int x) {
if (!p || x > r || x < l) return 1e9;
LL mid = (l + r) >> 1;
return min(Calc(x, tree[p]), min(query(ls[p], l, mid, x), query(rs[p], mid + 1, r, x)));
}
void AddSgt(long double k, long double b) {
l[++ tot] = {k, b};
update(rt, 1, M, tot);
}
int main() {
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> X[i] >> R[i] >> V[i];
}
F[1] = V[1]; AddSgt((long double)1 / 2 / sqrtl(R[1]), -(long double)X[1] / 2 / sqrtl(R[1]) + F[1]);
for (int i = 2; i <= n; i ++) {
F[i] = query(rt, 1, M, X[i]) + V[i];
AddSgt((long double)1 / 2 / sqrtl(R[i]), -(long double)X[i] / 2 / sqrtl(R[i]) + F[i]);
}
long double Ans = 1e18;
for (int i = 1; i <= n; i ++) {
if (X[i] + R[i] >= m) {
Ans = min(Ans, F[i]);
}
}
cout << fixed << setprecision(3) << Ans << "\n";
return 0;
}