#include<bits/stdc++.h>

using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define CIN_ONLY if(1)
struct cww {cww() {CIN_ONLY{ios::sync_with_stdio(false); cin.tie(0);}}
}star;
#define DEBUG if(0)
#endif

#define ALL(v) (v).begin(),(v).end()
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l, T r){bool a = l>r; if (a)l = r; return a;}
template <typename T>inline bool chmax(T &l, T r){bool a = l<r; if (a)l = r; return a;}
template <typename T>istream& operator>>(istream &is, vector<T> &v){for (auto &it : v)is >> it;return is;}

class range {private: struct I { int x; int operator*() { return x; }bool operator!=(I& lhs) { return x<lhs.x; }void operator++() { ++x; } }; I i, n;public:range(int n) :i({ 0 }), n({ n }) {}range(int i, int n) :i({ i }), n({ n }) {}I& begin() { return i; }I& end() { return n; }};
int N, M, S, G;
int x[212345];
int y[212345];
LL a[212345];
LL b[212345];
LL d[212345];
constexpr int X = 3;
LL bb[212345][X];
using V = vector<int>;
using VV = vector<V>;
using P = pair<LL, int>;
priority_queue<P> que;
void PUSH(int v,LL cost) {
	if (chmin(d[v],cost)) {
		que.push({ -cost,v });
	}
}
int POP() {
	auto p = que.top();
	que.pop();
	if (-p.first > d[p.second])return -1;
	return p.second;
}
LL ceil(LL a, LL b) {
	return (a + b - 1) / b;
}
LL get_min(LL a, LL b, LL k) {
	LL p = ceil(b ,a + k);
	LL ub = k;
	LL lb = -1;
	while (ub - lb > 1) {
		const LL mid = (lb + ub) / 2;
		if (ceil(b , (a + mid)) > p) {
			lb = mid;
		}
		else ub = mid;
	}
	return ub;
}
LL C(LL a, LL b, LL t, LL k=0) {
	return k + ceil(b, a + t);
}
LL get_next(LL a, LL b, LL k) {
	LL p = ceil(b ,(a + k));
	LL ub = 1e15;
	LL lb = k;
	
	while (ub - lb > 1) {
		const LL mid = (lb + ub) / 2;
		if (ceil(b , (a + mid)) < p) {
			ub = mid;
		}
		else lb = mid;
	}
	return ub;
}
LL get_prev(LL a, LL b, LL k) {
	if (k == 0)return 0;
	return get_min(a, b, get_min(a, b, k) - 1);
}
constexpr LL INF = 1e16;
LL get_root(LL b) {
	LL lb = 1;
	LL ub = b + 1;
	if (ub >= 1e9)ub = 1e9;
	while (ub - lb > 1) {
		const LL mid = (lb + ub) / 2;
		if (mid*mid <= b)lb = mid;
		else ub = mid;
	}
	return lb;
}
int main() {
	cin >> N >> M;
	cin >> S >> G;
	S--; G--;
	VV g(N);
	for (int i : range(M)) {
		cin >> x[i] >> y[i] >> a[i] >> b[i];
		x[i]--; y[i]--;
		g[x[i]].push_back(i);
		g[y[i]].push_back(i);
		//LL r = get_root(b[i]);
		LL lb = get_root(b[i])-a[i];
		for (int j : range(1))lb = get_prev(a[i], b[i], lb);
		for (int j : range(X)) {
			bb[i][j] = lb;
			if (a[i] + lb >= b[i])break;
			lb = get_next(a[i], b[i], lb);
		}

	}
	for (int i : range(N))d[i] = INF;
	PUSH(S, 0);
	while (que.size()) {
		int v = POP();
		if (v == -1)continue;
		for (int e : g[v]) {
			const int u = x[e] ^ y[e] ^ v;
			LL ans = d[v] + C(a[e], b[e], d[v]);
			if (a[e] + d[v] >= b[e]) {
				//PUSH(u, d[v] + 1);
			}
			else {
				/*
				LL ub = b[e] - a[e];
				LL lb = get_next(a[e], b[e], d[v]);
				while (ceil(b[e], a[e] + lb) - ceil(b[e], a[e] + ub) > 1 && ub - lb > 1) {
					LL mid = (lb + ub) / 2;
					mid = get_min(a[e], b[e], mid);
					if (mid == lb)mid = get_next(a[e], b[e], mid);
					LL mid_next = get_next(a[e], b[e], mid);
					if ((mid + C(a[e], b[e], mid)) < (mid_next + C(a[e], b[e], mid_next))) {
						ub = mid;
					}
					else lb = mid;

				}
				for (int i : range(6)) {
					PUSH(u, lb + C(a[e], b[e], lb));
					if (a[e] + lb  >= b[e])break;
					lb = get_next(a[e],b[e],lb);
				}
				*/
				for (int i : range(X)){
					if(d[v]<=bb[e][i])chmin(ans, bb[e][i] + C(a[e], b[e], bb[e][i]));
					if (a[e] + bb[e][i] >= b[e])break;
				}
			}
			PUSH(u, ans);
		}
	}
	if (d[G] == INF)cout << -1 << endl;
	else cout << d[G] << endl;
	return 0;
}



Measured memory_bytes: 30028