#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#define rep(i, a, b) for (int i = int(a); i < int(b); i++)
using namespace std;
using ll = long long int;
using P = pair<ll, ll>;

// clang-format off
#ifdef _DEBUG_
#define dump(...) do{ cerr << __LINE__ << ":\t" << #__VA_ARGS__ << " = "; debug_print(__VA_ARGS__); } while(false)
template<typename T, typename... Ts> void debug_print(const T &t, const Ts &...ts) { cerr << t; ((cerr << ", " << ts), ...); cerr << endl; }
#else
#define dump(...) do{ } while(false)
#endif
template<typename T> vector<T> make_v(size_t a, T b) { return vector<T>(a, b); }
template<typename... Ts> auto make_v(size_t a, Ts... ts) { return vector<decltype(make_v(ts...))>(a, make_v(ts...)); }
template<typename T> bool chmin(T &a, const T& b) { if (a > b) {a = b; return true; } return false; }
template<typename T> bool chmax(T &a, const T& b) { if (a < b) {a = b; return true; } return false; }
template<typename T, typename... Ts> void print(const T& t, const Ts&... ts) { cout << t; ((cout << ' ' << ts), ...); cout << '\n'; }
template<typename... Ts> void input(Ts&... ts) { (cin >> ... >> ts); }
template<typename T> istream &operator,(istream &in, T &t) { return in >> t; }
// clang-format on

using T = tuple<int, int, int>;
using Edge = tuple<ll, int>;
#include <queue>
#include <cmath>

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n, m;
    input(n, m);
    vector<vector<T>> g(n);
    rep(i, 0, m) {
        int a, b, c, d;
        input(a, b, c, d);
        a--;
        b--;
        g[a].emplace_back(b, c, d);
        g[b].emplace_back(a, c, d);
    }
    priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
    pq.emplace(0, 0);
    const ll inf = 1LL << 60;
    vector<ll> cost(n, inf);
    cost[0] = 0;
    while (pq.size()) {
        auto [cst, ver] = pq.top();
        pq.pop();
        if (cost[ver] < cst) continue;
        cost[ver] = cst;
        for (auto [nxt, c, d] : g[ver]) {
            ll ddiv = round(sqrt(d));
            for (ll t = max(ddiv - 2, 0LL); t <= ddiv + 2; t++) {
                ll nxtt = max(cst, t);
                nxtt += c + d / (nxtt + 1);
                if (chmin(cost[nxt], nxtt)) {
                    pq.emplace(nxtt, nxt);
                }
            }
        }
    }
    print(cost[n - 1] == inf ? -1 : cost[n - 1]);

    return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<map>
#include<ctime>
#include<queue>
#define mp make_pair
#define zjx printf("%d\n",
#define AK ans
#define IOI );
#define maxn 200005
#define lson now<<1
#define rson now<<1|1
using namespace std;
const int mod=998244353;
inline int read()
{
	int x=0;
	char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))x=x*10+c-'0',c=getchar();
	return x;
}
int n,m,p,h[100001];
struct pp
{
	int to,ne,v,w,t;
}a[200001];
void add(int x,int y,int z,int k)
{
	a[++p].to=y;
	a[p].ne=h[x];
	a[p].v=z;
	a[p].w=k;
	a[p].t=(int)(sqrt(k));
	h[x]=p;
}
long long d[100001];
int vis[100001];
struct node
{
	int id;
	long long num;
	node(int x,long long y)
	{
		id=x,num=y;
	}
	bool operator < (const node &x)const
	{
		return num>x.num;
	}
};
priority_queue<node>q; 
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),z=read(),k=read();
		add(x,y,z,k),add(y,x,z,k);
	}
	memset(d,0x3f,sizeof(d));
	d[1]=0;
	q.push(node(1,0));
	while(!q.empty())
	{
		int x=q.top().id;
		q.pop();
		if(vis[x])continue;
		vis[x]=1;
		for(int i=h[x];i;i=a[i].ne)
		{
			long long v=a[i].v+(d[x]<=a[i].t?(a[i].w/(a[i].t+1)+a[i].t):(a[i].w/(d[x]+1)+d[x]));
			if(d[a[i].to]>v)
			{
				d[a[i].to]=v;
				q.push(node(a[i].to,d[a[i].to]));
			}
		}
	}
	if(d[n]==0x3f3f3f3f3f3f3f3f)
	printf("-1");
	else
	printf("%lld",d[n]);
	return 0;
}