// competitive-verifier: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3044
#include "Other/golden_search.hpp"
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long N, M, S, G;
cin >> N >> M >> S >> G;
S--, G--;
vector<vector<tuple<int, long long, long long>>> edges(N);
for (int i = 0; i < M; i++)
{
long long U, V, A, B;
cin >> U >> V >> A >> B;
U--, V--;
edges[U].push_back({V, A, B});
edges[V].push_back({U, A, B});
}
vector<long long> dists(N, LONG_LONG_MAX);
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;
dists[S] = 0;
pq.push({0, S});
while (pq.size())
{
auto [dist, now] = pq.top();
pq.pop();
if (dists[now] < dist)
{
continue;
}
for (auto [next, A, B] : edges[now])
{
auto f = [&](double t) -> double
{
return t + (double)B / (t + (double)A);
};
auto start = golden_search<true, double>(dist, 1e20, f).first;
auto f_int = [&](long long t) -> long long
{
return t + (B + t + A - 1) / (t + A);
};
long long next_dist = min(f_int(floor(start)), f_int(ceil(start)));
if (dists[next] <= next_dist)
{
continue;
}
dists[next] = next_dist;
pq.push({next_dist, next});
}
}
long long ans = dists[G];
if (ans == LONG_LONG_MAX)
{
ans = -1;
}
cout << ans << endl;
return 0;
};
#line 1 "test/Other/golden_search/aoj-3044.cpp"
// competitive-verifier: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3044
#line 1 "Other/golden_search.hpp"
#include <bits/stdc++.h>
using namespace std;
// フィボナッチ数列による三分探索。「狭義」凸関数の極値を探索する。返り値は{x, f(x)}
template <bool Minimize, typename T>
pair<double, T> golden_search(double x_low, double x_high, function<T(double)> f)
{
assert(x_low <= x_high);
auto comp = [](T a, T b) -> bool
{
return Minimize ? a <= b : a >= b;
};
const double PHI = 1.61803398874989484; // (1 + √5) / 2
const double DIVPHI = 0.381966011250105151; // 1 / (1 + PHI);
double x_mid_low = (x_low * PHI + x_high) * DIVPHI;
double x_mid_high = (x_low + x_high * PHI) * DIVPHI;
double f_low = f(x_low), f_mid_low = f(x_mid_low), f_mid_high = f(x_mid_high), f_high = f(x_high);
for (int iter = 0; iter < 100; iter++)
{
if (comp(f_mid_low, f_mid_high))
{
tie(x_mid_low, x_mid_high, x_high) = tuple<double, double, double>{(x_low * PHI + x_mid_high) * DIVPHI, x_mid_low, x_mid_high};
tie(f_mid_low, f_mid_high, f_high) = tuple<double, double, double>{f(x_mid_low), f_mid_low, f_mid_high};
}
else
{
tie(x_low, x_mid_low, x_mid_high) = tuple<double, double, double>{x_mid_low, x_mid_high, (x_mid_low + x_high * PHI) * DIVPHI};
tie(f_low, f_mid_low, f_mid_high) = tuple<double, double, double>{f_mid_low, f_mid_high, f(x_mid_high)};
}
}
return {x_low, f_low};
}
#line 5 "test/Other/golden_search/aoj-3044.cpp"
using namespace std;
int main()
{
long long N, M, S, G;
cin >> N >> M >> S >> G;
S--, G--;
vector<vector<tuple<int, long long, long long>>> edges(N);
for (int i = 0; i < M; i++)
{
long long U, V, A, B;
cin >> U >> V >> A >> B;
U--, V--;
edges[U].push_back({V, A, B});
edges[V].push_back({U, A, B});
}
vector<long long> dists(N, LONG_LONG_MAX);
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;
dists[S] = 0;
pq.push({0, S});
while (pq.size())
{
auto [dist, now] = pq.top();
pq.pop();
if (dists[now] < dist)
{
continue;
}
for (auto [next, A, B] : edges[now])
{
auto f = [&](double t) -> double
{
return t + (double)B / (t + (double)A);
};
auto start = golden_search<true, double>(dist, 1e20, f).first;
auto f_int = [&](long long t) -> long long
{
return t + (B + t + A - 1) / (t + A);
};
long long next_dist = min(f_int(floor(start)), f_int(ceil(start)));
if (dists[next] <= next_dist)
{
continue;
}
dists[next] = next_dist;
pq.push({next_dist, next});
}
}
long long ans = dists[G];
if (ans == LONG_LONG_MAX)
{
ans = -1;
}
cout << ans << endl;
return 0;
};