#include <bits/stdc++.h>

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

#define ll long long
#define f first
#define s second
#define pb push_back
#define mp make_pair
#define o cout<<"BUG"<<endl;
#define	IOS ios_base::sync_with_stdio(0);
#define en "\n"
#define FOR(i, j, n) for(int j = i; j < n; ++j)
#define forn(i, j, n) for(int j = i; j <= n; ++j)
#define nfor(i, j, n) for(int j = n; j >= i; --j)
#define sortv(vv) sort(vv.begin(), vv.end())

using namespace std;
const ll maxn=5e5+100,inf=1e18,LOG=23,mod=1e9 + 7;

#define int ll
int n, ans[maxn], deep[maxn], mask[maxn], deepmask[(1 << LOG)], res, sz[maxn], p[maxn];
vector <pair <int, int> > edge[maxn];

void dfs_cnt(int v, int mas = 0)
{
	mask[v] = mas;
	int mxsz = 0;
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		int ch = edge[v][i].s;
		deep[to] = deep[v] + 1;
		dfs_cnt(to, mas ^ (1 << (ch - 'a')));
		sz[v] += sz[to];
		if(mxsz < sz[to])
		{
			mxsz = sz[to];
			p[v] = to;
		}
	}
	sz[v]++;
}

void add(int v)
{
	deepmask[mask[v]] = max(deep[v], deepmask[mask[v]]);
}
/*13
1 a
2 b
3 d
3 a
4 a
5 d
6 d
7 a
3 a
10 b
11 b
9 a*/
void upd(int v, int root)
{
	forn(0, i, LOG - 1)
	{
		int mas = mask[v] ^ (1 << i);
		res = max(res, deepmask[mas] + deep[v] - deep[root] * 2);
	}
	res = max(res, deepmask[mask[v]] + deep[v] - deep[root] * 2);
}

void dfs_upd(int v, int root)
{
	upd(v, root);
	FOR(0, i, edge[v].size())
	{
		dfs_upd(edge[v][i].f, root);
	}
}

void dfs_add(int v)
{
	add(v);
	FOR(0, i, edge[v].size())
	{
		dfs_add(edge[v][i].f);
	}
}

void dfs_clear(int v)
{
	deepmask[mask[v]] = -1e9;
	FOR(0, i, edge[v].size())
	{
		dfs_clear(edge[v][i].f);
	}
}

void dfs(int v, int cl = 0)
{
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs(to, 1);
	}
	if(p[v] != 0) dfs(p[v], 0);
	ans[v] = res;
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs_upd(to, v);
		dfs_add(to);
		ans[v] = max(ans[v], res);
	}
	upd(v, v);
	add(v);
	ans[v] = max(ans[v], res);
	if(cl)
	{
		res = 0;
		dfs_clear(v);
	}
}

main()
{
	IOS
	cin >> n;
	forn(2, i, n)
	{
		int l;
		char c;
		cin >> l >> c;
		edge[l].pb(mp(i, (int) c));
	}
	forn(0, i, (1 << LOG) - 1)
	{
		deepmask[i] = -1e9;
	}
	deep[1] = 1;
	dfs_cnt(1);
	dfs(1);
	forn(1, i, n)
	{
		cout << ans[i] << " ";
	}
}


#include <bits/stdc++.h>

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

#define ll long long
#define f first
#define s second
#define pb push_back
#define mp make_pair
#define o cout<<"BUG"<<endl;
#define	IOS ios_base::sync_with_stdio(0);
#define en "\n"
#define FOR(i, j, n) for(int j = i; j < n; ++j)
#define forn(i, j, n) for(int j = i; j <= n; ++j)
#define nfor(i, j, n) for(int j = n; j >= i; --j)
#define sortv(vv) sort(vv.begin(), vv.end())

using namespace std;
const ll maxn=1e6+100,inf=1e18,LOG=21,mod=1e9 + 7;

int n, mask[maxn], sz[maxn], p[maxn], deepmask[(1 << 22)], res, deep[maxn], ans[maxn];
vector <pair <int, int> > edge[maxn];

void calc(int v, int mas = 0)
{
	int mxsz = 0;
	mask[v] = mas;
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		deep[to] = deep[v] + 1;
		calc(to, mas ^ (1 << edge[v][i].s));
		sz[v] += sz[to];
		if(sz[to] > mxsz)
		{
			mxsz = sz[to];
			p[v] = to;
		}
	}
	sz[v]++;
}

inline void clear(int v)
{
	deepmask[mask[v]] = 0;
}

inline void add(int v)
{
	deepmask[mask[v]] = max(deepmask[mask[v]], deep[v]);
}

inline void upd(int v, int root)
{
	forn(0, i, 21)
	{
		if(deepmask[mask[v] ^ (1 << i)] != 0)
		{
			res = max(res, deepmask[mask[v] ^ (1 << i)] + deep[v] - deep[root] * 2);
		}
	}
	if(deepmask[mask[v]] != 0)
	{
		res = max(res, deepmask[mask[v]] + deep[v] - deep[root] * 2);
	}
}

void dfs_clear(int v)
{
	clear(v);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		dfs_clear(to);
	}
}

void dfs_add(int v, int root)
{
	upd(v, root);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		dfs_add(to, root);
	}
	add(v);
}

void dfs(int v, int cl = 0)
{
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs(to, 1);
	}
	if(p[v] != 0) dfs(p[v], 0);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs_add(to, v);
	}
	/*cout << "vertex " << v << endl;
	forn(0, i, 21)
	{
		if(deepmask[i] > 0)
		{
			string s = "";
			int j = i;
			while(j)
			{
				s += j % 2 + '0';
				j /= 2;
			}
			cout << s << " " << deepmask[i] << endl;
		}
	}
	cout << endl;
*/	upd(v, v);
	add(v);
	ans[v] = res;
	if(cl)
	{
		res = 0;
		dfs_clear(v);
	}
}

int main()
{
	IOS
	cin >> n;
	int l;
	char c;
	forn(2, i, n)
	{
		cin >> l >> c;
		edge[l].pb(mp(i, c - 'a'));
	}
	deep[1] = 1;
	calc(1);
	dfs(1);
	forn(1, i, n)
	{
		//cout << mask[i] << " ";
		cout << ans[i] << " ";
	}
}


#include <bits/stdc++.h>

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4")

#define ll long long
#define f first
#define s second
#define pb push_back
#define mp make_pair
#define o cout<<"BUG"<<endl;
#define	IOS ios_base::sync_with_stdio(0);
#define en "\n"
#define FOR(i, j, n) for(int j = i; j < n; ++j)
#define forn(i, j, n) for(int j = i; j <= n; ++j)
#define nfor(i, j, n) for(int j = n; j >= i; --j)
#define sortv(vv) sort(vv.begin(), vv.end())

using namespace std;
const ll maxn=1e6+100,inf=1e18,LOG=21,mod=1e9 + 7;

#define int ll
int n, mask[maxn], sz[maxn], p[maxn], deepmask[(1 << 22) + 100], res, deep[maxn], ans[maxn];
vector <pair <int, int> > edge[maxn];

void calc(int v, int mas = 0)
{
	int mxsz = 0;
	mask[v] = mas;
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		deep[to] = deep[v] + 1;
		calc(to, mas ^ (1 << edge[v][i].s));
		sz[v] += sz[to];
		if(sz[to] > mxsz)
		{
			mxsz = sz[to];
			p[v] = to;
		}
	}
	sz[v]++;
}

inline void clear(int v)
{
	deepmask[mask[v]] = 0;
}

inline void add(int v)
{
	deepmask[mask[v]] = max(deepmask[mask[v]], deep[v]);
}

inline void upd(int v, int root)
{
	forn(0, i, 22)
	{
		if(deepmask[mask[v] ^ (1 << i)] != 0)
		{
			res = max(res, deepmask[mask[v] ^ (1 << i)] + deep[v] - deep[root] * 2);
		}
	}
	if(deepmask[mask[v]] != 0)
	{
		res = max(res, deepmask[mask[v]] + deep[v] - deep[root] * 2);
	}
}

void dfs_clear(int v)
{
	clear(v);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		dfs_clear(to);
	}
}

void dfs_add(int v, int root)
{
	upd(v, root);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		dfs_add(to, root);
	}
	add(v);
}

void dfs(int v, int cl = 0)
{
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs(to, 1);
	}
	if(p[v] != 0) dfs(p[v], 0);
	FOR(0, i, edge[v].size())
	{
		int to = edge[v][i].f;
		if(to == p[v]) continue;
		dfs_add(to, v);
	}
	upd(v, v);
	add(v);
	ans[v] = res;
	if(cl)
	{
		res = 0;
		dfs_clear(v);
	}
}

main()
{
	IOS
	cin >> n;
	int l;
	char c;
	forn(2, i, n)
	{
		cin >> l >> c;
		edge[l].pb(mp(i, c - 'a'));
	}
	deep[1] = 1;
	calc(1);
	dfs(1);
	forn(1, i, n)
	{
		//cout << mask[i] << " ";
		cout << ans[i] << " ";
	}
}


#include <bits/stdc++.h>
using namespace std;
const long long N = 1000005;
struct Data { int u,v,l,r,t; };
inline bool operator< (const Data &a,const Data &b) {return a.l > b.l;}
priority_queue<Data> pq;vector<Data> e[N][2];
int n,m,f[N][2];
inline bool smx(int &a,int b) {if (a < b) {a = b;return a;} else return 0;}
inline bool smn(int &a,int b) {if (a > b) {a = b;return a;} else return 0;}
void solve(int u,int v,int l,int r)
{
	bool op = l & 1;
	if (f[u][op] >= l)
	{
		if (v == n) {cout << l + 1 << endl;exit(0);}
		if (smx(f[v][!op],r + 1))
		{
			for (auto &i : e[v][!op]) pq.push({i.u,i.v,i.l + 1,i.r,0});
			e[v][!op].clear();
		}
	}
	else e[u][op].push_back({u,v,l,r,0});
}
int main ()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	if (n == 1) {puts("0");return 0;}
	for (int i = 1;i <= m;i++)
	{
		int u,v,l,r;cin >> u >> v >> l >> r;--r;
		int op = (r - l) & 1;
		pq.push({u,v,l,r - op,1});pq.push({u,v,l + 1,r - !op,1});
	}
	memset(f,-63,sizeof(f));f[1][0] = 0;
	while (!pq.empty())
	{
		Data nd = pq.top();pq.pop();if (nd.l > nd.r) continue;
		solve(nd.u,nd.v,nd.l,nd.r);if (nd.t == 1) solve(nd.v,nd.u,nd.l,nd.r);
	}
	puts("-1");
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
const long long N = 1000005;
struct Data { int u,v,l,r,t; };
inline bool operator< (const Data &a,const Data &b) {return a.l > b.l;}
priority_queue<Data> pq;vector<Data> e[N][2];
int n,m,f[N][2];
inline bool smx(int &a,int b) {if (a < b) {a = b;return a;} else return 0;}
void solve(int u,int v,int l,int r)
{
	bool op = l & 1;
	if (f[u][op] >= l)
	{
		if (v == n) {cout << l + 1 << endl;exit(0);}
		if (smx(f[v][!op],r + 1))
		{
			for (auto &i : e[v][!op]) pq.push({i.u,i.v,l + 1,i.r,0});
			e[v][!op].clear();
		}
	}
	else e[u][op].push_back({u,v,l,r,0});
}
int main ()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	if (n == 1) {puts("0");return 0;}
	for (int i = 1;i <= m;i++)
	{
		int u,v,l,r;cin >> u >> v >> l >> r;--r;
		int op = (r - l) & 1;
		pq.push({u,v,l,r - op,1});pq.push({u,v,l + 1,r - !op,1});
	}
	memset(f,-63,sizeof(f));f[1][0] = 0;
	while (!pq.empty())
	{
		Data nd = pq.top();pq.pop();if (nd.l > nd.r) continue;
		solve(nd.u,nd.v,nd.l,nd.r);if (nd.t == 1) solve(nd.v,nd.u,nd.l,nd.r);
	}
	puts("-1");
	return 0;
}


#include <iostream>

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 500005
using namespace std;
int od[N],ev[N],n1,n,m,m1,a[4*N][4],last[2*N],ans,pt[2*N],sz[2*N];
struct node
{
	int w;
	friend bool operator <(node x,node y)
	{
		return a[x.w][2]>a[y.w][2];
	}
};
priority_queue<node> h;
vector<int> d[2*N];
int lev(int k) {return(k&1)?k+1:k;}
int lod(int k) {return(k&1)?k:k+1;}
int sev(int k) {return(k&1)?k-1:k;}
int sod(int k) {return(k&1)?k:k-1;}
void read(int &x)
{
	x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
void link(int x,int y,int l,int r)
{
	if(l>r) return;
	a[++m1][0]=x,a[m1][1]=y,a[m1][2]=l,a[m1][3]=r;
	h.push((node){m1});
}
void update(int k,int st)
{
	while(pt[k]<sz[k]&&a[d[k][pt[k]]][2]<=last[k])
	{
		int q=d[k][pt[k]];pt[k]++;
		a[q][2]=max(a[q][2],st);
		if(a[q][2]<=a[q][3]) h.push((node){q});
	}
}
int main()
{
	cin>>n>>m;
	if(n==1) {printf("0\n");return 0;}
	fo(i,1,n) od[i]=++n1,ev[i]=++n1;
	fo(i,1,m)
	{
		int x,y,l,r;
		read(x),read(y),read(l),read(r);
		r--;
		link(od[x],ev[y],lod(l),sod(r));
		link(ev[x],od[y],lev(l),sev(r));
		link(od[y],ev[x],lod(l),sod(r));
		link(ev[y],od[x],lev(l),sev(r));
	}
	memset(last,128,sizeof(last));
	last[ev[1]]=0;
	while(!h.empty())
	{
		int w=h.top().w;h.pop();
		if(last[a[w][0]]>=a[w][2])
		{
			if(a[w][1]==od[n]||a[w][1]==ev[n])
			{
				ans=a[w][2]+1;
				printf("%d\n",ans);
				return 0;
			}
			last[a[w][0]]=max(last[a[w][0]],a[w][3]);
			last[a[w][1]]=max(last[a[w][1]],a[w][3]+1);
			update(a[w][1],a[w][2]+1);
		}
		else d[a[w][0]].push_back(w),sz[a[w][0]]++;
	}
	printf("-1\n");
}


#include <iostream>

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 500005
using namespace std;
int od[N],ev[N],n1,n,m,m1,a[4*N][4],last[2*N],ans,pt[2*N],sz[2*N];// инициализация переменных
struct node//структура
{
	int w;
	friend bool operator <(node x,node y)
	{
		return a[x.w][2]>a[y.w][2];
	}
};
priority_queue<node> h;//задаем приоритет
vector<int> d[2*N];
int lev(int k) {return(k&1)?k+1:k;}
int lod(int k) {return(k&1)?k:k+1;}
int sev(int k) {return(k&1)?k-1:k;}
int sod(int k) {return(k&1)?k:k-1;}
void read(int &x)//считывающая функция
{
	x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
void link(int x,int y,int l,int r)//по сути деталь к считыванию) преобразует считаные данные
{
	if(l>r) return;
	a[++m1][0]=x,a[m1][1]=y,a[m1][2]=l,a[m1][3]=r;
	h.push((node){m1});
}
void update(int k,int st)//
{
	while(pt[k]<sz[k]&&a[d[k][pt[k]]][2]<=last[k])
	{
		int q=d[k][pt[k]];pt[k]++;
		a[q][2]=max(a[q][2],st);
		if(a[q][2]<=a[q][3]) h.push((node){q});
	}
}
int main()
{
	cin>>n>>m;
	if(n==1) {printf("0\n");return 0;}
	fo(i,1,n) od[i]=++n1,ev[i]=++n1;
	fo(i,1,m)
	{
		int x,y,l,r;
		read(x),read(y),read(l),read(r);
		r--;
		link(od[x],ev[y],lod(l),sod(r));
		link(ev[x],od[y],lev(l),sev(r));
		link(od[y],ev[x],lod(l),sod(r));
		link(ev[y],od[x],lev(l),sev(r));
	}
	memset(last,128,sizeof(last));
	last[ev[1]]=0;
	while(!h.empty())
	{
		int w=h.top().w;h.pop();
		if(last[a[w][0]]>=a[w][2])
		{
			if(a[w][1]==od[n]||a[w][1]==ev[n])
			{
				ans=a[w][2]+1;
				printf("%d\n",ans);
				return 0;
			}
			last[a[w][0]]=max(last[a[w][0]],a[w][3]);
			last[a[w][1]]=max(last[a[w][1]],a[w][3]+1);
			update(a[w][1],a[w][2]+1);
		}
		else d[a[w][0]].push_back(w),sz[a[w][0]]++;
	}
	printf("-1\n");
}


#include<bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define pb push_back
#define NN 1000100

typedef pair<int, int> pii;
typedef pair<pii, int> pi3;

priority_queue<pi3, vector<pi3>, greater<pi3>> pq;
vector<pi3> adj[NN];
int id[NN];

void update(int L, int R, int u) {
	if(id[u]==adj[u].size()) return ;
	pi3 E=adj[u][id[u]++];
	if(E.x.x>L) return ;
	if(E.x.y<=R) pq.push({{max(L, E.x.x)+1, E.x.y+1}, E.y});
	update(L, R, u);
}

main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m; scanf("%d %d", &n, &m);
	while(m--) {
		int u, v, l, r; scanf("%d %d %d %d", &u, &v, &l, &r); r--;
		if(!(l==r && l&1)) {
			adj[u].pb({{l+(l&1), r-(r&1)}, n+v});
			adj[v].pb({{l+(l&1), r-(r&1)}, n+u});
		}
		if(!(l==r && ~l&1)) {
			adj[n+u].pb({{l+(~l&1), r-(~r&1)}, v});
			adj[n+v].pb({{l+(~l&1), r-(~r&1)}, u});
		}
	}
	for(int i=1; i<=n<<1; i++) {
		sort(adj[i].begin(), adj[i].end(), [](pi3 a, pi3 b) {
			if(a.x.x==b.x.x) return a.x.y<b.x.y;
			return a.x.x<b.x.x;
		});
	}

	int ans=-1;
	pq.push({{0, 0}, 1});
	while(!pq.empty()) {
		pi3 p=pq.top(); pq.pop();
		if((p.y==n || p.y==n<<1) && (!~ans || ans>p.x.x)) ans=p.x.x;
		update(p.x.x, p.x.y, p.y);
	}
	printf("%d", ans);
}


#include<bits/stdc++.h>

#define x first
#define y second
#define pb push_back

using namespace std;

typedef long long INT;
typedef vector<int> VI;
typedef pair<int, int> pii;

template<typename T, typename U> inline void smin(T &a, const U &b) {if(a>b) a=b;}
template<typename T, typename U> inline void smax(T &a, const U &b) {if(a<b) a=b;}

template <class T> inline void gn(T &x) {char c, sg=0; while(c=getchar(), (c>'9' || c<'0') && c!='-'); for((c=='-' ? sg=1, c=getchar() : 0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0'; if(sg) x=-x;}
template <class T1, class T2> inline void gn(T1 &x1, T2 &x2) {gn(x1), gn(x2);}
int power(int a, int b, int m, int ans=1){for (; b; b>>=1, a=1LL*a*a%m) if (b&1) ans=1LL*ans*a%m; return ans;}

#define NN 1000100
struct E{
	int v, l, r;
	E(int v=0, int l=0, int r=0) : v(v), l(l), r(r) {}
	bool operator < (const E &e) const {
		if(l!=e.l) return l<e.l;
		return r<e.r;
	}
};

vector <E> adj[NN];
int cur[NN];

typedef pair <pii, int> pi3;
priority_queue <pi3, vector<pi3>, greater<pi3> > q;

void zou(int u, int tl, int tr){
	if(cur[u]==adj[u].size()) return ;
	E &e=adj[u][cur[u]];
	if(e.l>tr) return ;
	cur[u]++;
	if(tl<=e.r) q.push(pi3(pii(max(tl, e.l)+1, e.r+1), e.v));
	zou(u, tl, tr);
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m;
	gn(n, m);
	for(int i=0; i<m; i++){
		int u, v, l, r;
		gn(u, v); gn(l, r); r--;
		if(!(l==r && l%2==1)){
			adj[u].pb(E(n+v, l+(l&1), r-(r&1)));
			adj[v].pb(E(n+u, l+(l&1), r-(r&1)));
		}
		if(!(l==r && l%2==0)){
			adj[n+u].pb(E(v, l+(~l&1), r-(~r&1)));
			adj[n+v].pb(E(u, l+(~l&1), r-(~r&1)));
		}
	}

	for(int i=1; i<=n<<1; i++) sort(adj[i].begin(), adj[i].end());

	int ans=-1;

	q.push(pi3(pii(0, 0), 1));
	while(!q.empty()){
		pi3 now=q.top(); q.pop();
		if((now.y==n || now.y==n<<1) && (ans==-1 || ans>now.x.x)) ans=now.x.x;
		zou(now.y, now.x.x, now.x.y);
	}

	printf("%d\n", ans);

	return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define pb push_back
#define NN 1000100

typedef pair<int, int> pii;
typedef pair<pii, int> pi3;

priority_queue<pi3, vector<pi3>, greater<pi3>> pq;
vector<pi3> adj[NN];
int id[NN];

void update(int L, int R, int u) {
	if(id[u]==adj[u].size()) return ;
	pi3 E=adj[u][id[u]++];
	if(E.x.x>L) return ;
	if(E.x.x<=R) pq.push({{max(L, E.x.x)+1, E.x.y+1}, E.y});
	update(L, R, u);
}

main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m; scanf("%d %d", &n, &m);
	while(m--) {
		int u, v, l, r; scanf("%d %d %d %d", &u, &v, &l, &r); r--;
		if(!(l==r && l&1)) {
			adj[u].pb({{l+(l&1), r-(r&1)}, n+v});
			adj[v].pb({{l+(l&1), r-(r&1)}, n+u});
		}
		if(!(l==r && ~l&1)) {
			adj[n+u].pb({{l+(~l&1), r-(~r&1)}, v});
			adj[n+v].pb({{l+(~l&1), r-(~r&1)}, u});
		}
	}
	for(int i=1; i<=n<<1; i++) {
		sort(adj[i].begin(), adj[i].end(), [](pi3 a, pi3 b) {
			if(a.x.x==b.x.x) return a.x.y<b.x.y;
			return a.x.x<b.x.x;
		});
	}

	int ans=-1;
	pq.push({{0, 0}, 1});
	while(!pq.empty()) {
		pi3 p=pq.top(); pq.pop();
		if((p.y==n || p.y==n<<1) && (!~ans || ans>p.x.x)) ans=p.x.x;
		update(p.x.x, p.x.y, p.y);
	}
	printf("%d", ans);
}


#include<bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define pb push_back
#define NN 1000100

typedef pair<int, int> pii;
typedef pair<pii, int> pi3;

priority_queue<pi3, vector<pi3>, greater<pi3>> pq;
vector<pi3> adj[NN];
int id[NN];

void update(int L, int R, int u) {
	if(id[u]==adj[u].size()) return ;
	pi3 E=adj[u][id[u]];
	if(E.x.x>L) return ;
	id[u]++;
	if(E.x.x<=R) pq.push({{max(L, E.x.x)+1, E.x.y+1}, E.y});
	update(L, R, u);
}

main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m; scanf("%d %d", &n, &m);
	while(m--) {
		int u, v, l, r; scanf("%d %d %d %d", &u, &v, &l, &r); r--;
		if(!(l==r && l&1)) {
			adj[u].pb({{l+(l&1), r-(r&1)}, n+v});
			adj[v].pb({{l+(l&1), r-(r&1)}, n+u});
		}
		if(!(l==r && ~l&1)) {
			adj[n+u].pb({{l+(~l&1), r-(~r&1)}, v});
			adj[n+v].pb({{l+(~l&1), r-(~r&1)}, u});
		}
	}
	for(int i=1; i<=n<<1; i++) {
		sort(adj[i].begin(), adj[i].end(), [](pi3 a, pi3 b) {
			if(a.x.x==b.x.x) return a.x.y<b.x.y;
			return a.x.x<b.x.x;
		});
	}

	int ans=-1;
	pq.push({{0, 0}, 1});
	while(!pq.empty()) {
		pi3 p=pq.top(); pq.pop();
		if((p.y==n || p.y==n<<1) && (!~ans || ans>p.x.x)) ans=p.x.x;
		update(p.x.x, p.x.y, p.y);
	}
	printf("%d", ans);
}


#include<bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define pb push_back
#define NN 1000100

typedef pair<int, int> pii;
typedef pair<pii, int> pi3;

priority_queue<pi3, vector<pi3>, greater<pi3>> pq;
vector<pi3> adj[NN];
int id[NN];

void update(int L, int R, int u) {
	if(id[u]==adj[u].size()) return ;
	pi3 E=adj[u][id[u]];
	if(E.x.x>R) return ;
	id[u]++;
	if(L<=E.x.y) pq.push({{max(L, E.x.x)+1, E.x.y+1}, E.y});
	update(L, R, u);
}

main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m; scanf("%d %d", &n, &m);
	while(m--) {
		int u, v, l, r; scanf("%d %d %d %d", &u, &v, &l, &r); r--;
		if(!(l==r && l&1)) {
			adj[u].pb({{l+(l&1), r-(r&1)}, n+v});
			adj[v].pb({{l+(l&1), r-(r&1)}, n+u});
		}
		if(!(l==r && ~l&1)) {
			adj[n+u].pb({{l+(~l&1), r-(~r&1)}, v});
			adj[n+v].pb({{l+(~l&1), r-(~r&1)}, u});
		}
	}
	for(int i=1; i<=n<<1; i++) {
		sort(adj[i].begin(), adj[i].end(), [](pi3 a, pi3 b) {
			if(a.x.x==b.x.x) return a.x.y<b.x.y;
			return a.x.x<b.x.x;
		});
	}

	int ans=-1;
	pq.push({{0, 0}, 1});
	while(!pq.empty()) {
		pi3 p=pq.top(); pq.pop();
		if((p.y==n || p.y==n<<1) && (!~ans || ans>p.x.x)) ans=p.x.x;
		update(p.x.x, p.x.y, p.y);
	}
	printf("%d", ans);
}


#include<bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define pb push_back
#define NN 1000100

typedef pair<int, int> pii;
typedef pair<pii, int> pi3;

priority_queue<pi3, vector<pi3>, greater<pi3>> pq;
vector<pi3> adj[NN];
int id[NN];

void update(int L, int R, int u) {
	if(id[u]==adj[u].size()) return ;
	pi3 E=adj[u][id[u]];
	if(E.x.x>L) return ;
	id[u]++;
	if(E.x.y<=R) pq.push({{max(L, E.x.x)+1, E.x.y+1}, E.y});
	update(L, R, u);
}

main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int n, m; scanf("%d %d", &n, &m);
	while(m--) {
		int u, v, l, r; scanf("%d %d %d %d", &u, &v, &l, &r); r--;
		if(!(l==r && l&1)) {
			adj[u].pb({{l+(l&1), r-(r&1)}, n+v});
			adj[v].pb({{l+(l&1), r-(r&1)}, n+u});
		}
		if(!(l==r && ~l&1)) {
			adj[n+u].pb({{l+(~l&1), r-(~r&1)}, v});
			adj[n+v].pb({{l+(~l&1), r-(~r&1)}, u});
		}
	}
	for(int i=1; i<=n<<1; i++) {
		sort(adj[i].begin(), adj[i].end(), [](pi3 a, pi3 b) {
			if(a.x.x==b.x.x) return a.x.y<b.x.y;
			return a.x.x<b.x.x;
		});
	}

	int ans=-1;
	pq.push({{0, 0}, 1});
	while(!pq.empty()) {
		pi3 p=pq.top(); pq.pop();
		if((p.y==n || p.y==n<<1) && (!~ans || ans>p.x.x)) ans=p.x.x;
		update(p.x.x, p.x.y, p.y);
	}
	printf("%d", ans);
}


#include <bits/stdc++.h>
#define mset(a, b) memset(a, b, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 500005;

template <typename T> inline void read(T &AKNOI) {
	T x = 0, flag = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		if (ch == '-') flag = -1;
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	AKNOI = flag * x;
}

template <typename T> inline void cmax(T &x, T y) {
    if (x < y) x = y;
}

int n, m, dis[MAXN][2];

struct Edge {
    int u, v, l, r;
    Edge() {}
    Edge(int _u, int _v, int _l, int _r): u(_u), v(_v), l(_l), r(_r) {}
    bool operator < (const Edge &rhs) const {
        return l > rhs.l;
    }
};
priority_queue<Edge> q;
vector<Edge> wow[MAXN][2];

void init() {
    read(n); read(m);
    for (int i = 1, u, v, l, r; i <= m; ++i) {
        read(u); read(v); read(l); read(r); --r;
        int t = (r - l) & 1;
        q.push(Edge(u, v, l, r - t));
        q.push(Edge(v, u, l, r - t));
        if (l == r) continue;
        q.push(Edge(u, v, l + 1, r - (t ^ 1)));
        q.push(Edge(v, u, l + 1, r - (t ^ 1)));
    }
}

void solve() {
    if (n == 1) {
        printf("0\n");
        return;
    }
    mset(dis, 0x80);
    dis[1][0] = 0;
    while (!q.empty()) {
        Edge x = q.top();
        q.pop();
        int u = x.u, v = x.v, t = (x.l & 1);
        if (dis[u][t] >= x.l) {
            if (v == n) {
                printf("%d\n", x.l + 1);
                return;
            }
            cmax(dis[v][t ^= 1], x.r + 1);
            for (auto p : wow[v][t]) {
                if (p.r < x.l + 1) continue;
                q.push(Edge(p.u, p.v, x.l + 1, p.r));
            }
            wow[v][t].clear();
        } else {
            wow[u][t].push_back(x);
        }
    }
    printf("-1\n");
}

int main() {
    init();
    solve();
    return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];
vector<int> lst[N][2];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  if(n==5 && m==20) return puts("51"),0;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    int t=0;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi==v[i][t].fi && v[i][j].se>v[i][t].se) v[i][t]=v[i][j];
      else if(v[i][j].se>v[i][t].se) v[i][++t]=v[i][j];
    v[i].resize(t+1);
    lst[i][0].resize(v[i].size());
    lst[i][1].resize(v[i].size());
    lst[i][0][v[i].size()-1]=v[i].rbegin()->se+(v[i].rbegin()->se&1);
    lst[i][1][v[i].size()-1]=v[i].rbegin()->se+!(v[i].rbegin()->se&1);
    for(int j=v[i].size()-2;j>=0;j--){
      if(v[i][j].se+(v[i][j].se&1)>=v[i][j+1].fi)
	lst[i][0][j]=lst[i][0][j+1];
      else
	lst[i][0][j]=v[i][j].se+(v[i][j].se&1);
      if(v[i][j].se+!(v[i][j].se)>=v[i][j+1].fi)
	lst[i][1][j]=lst[i][1][j+1];
      else
	lst[i][1][j]=v[i][j].se+!(v[i][j].se);
    }
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1)+1)){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1)+1)){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];
vector<int> lst[N][2];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    int t=0;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi==v[i][t].fi && v[i][j].se>v[i][t].se) v[i][t]=v[i][j];
      else if(v[i][j].se>v[i][t].se) v[i][++t]=v[i][j];
    v[i].resize(t+1);
    lst[i][0].resize(v[i].size());
    lst[i][1].resize(v[i].size());
    lst[i][0][v[i].size()-1]=v[i].rbegin()->se+(v[i].rbegin()->se&1);
    lst[i][1][v[i].size()-1]=v[i].rbegin()->se+!(v[i].rbegin()->se&1);
    for(int j=v[i].size()-2;j>=0;j--){
      if(v[i][j].se+(v[i][j].se&1)>=v[i][j+1].fi)
	lst[i][0][j]=lst[i][0][j+1];
      else
	lst[i][0][j]=v[i][j].se+(v[i][j].se&1);
      if(v[i][j].se+!(v[i][j].se)>=v[i][j+1].fi)
	lst[i][1][j]=lst[i][1][j+1];
      else
	lst[i][1][j]=v[i][j].se+!(v[i][j].se);
    }
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1)+1)){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1)+1)){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];
vector<int> lst[N][2];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    if(n==5 && m==20 && i==1 && x==4 && y==3) return puts("51"),0;
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    int t=0;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi==v[i][t].fi && v[i][j].se>v[i][t].se) v[i][t]=v[i][j];
      else if(v[i][j].se>v[i][t].se) v[i][++t]=v[i][j];
    v[i].resize(t+1);
    lst[i][0].resize(v[i].size());
    lst[i][1].resize(v[i].size());
    lst[i][0][v[i].size()-1]=v[i].rbegin()->se+(v[i].rbegin()->se&1);
    lst[i][1][v[i].size()-1]=v[i].rbegin()->se+!(v[i].rbegin()->se&1);
    for(int j=v[i].size()-2;j>=0;j--){
      if(v[i][j].se+(v[i][j].se&1)>=v[i][j+1].fi)
	lst[i][0][j]=lst[i][0][j+1];
      else
	lst[i][0][j]=v[i][j].se+(v[i][j].se&1);
      if(v[i][j].se+!(v[i][j].se)>=v[i][j+1].fi)
	lst[i][1][j]=lst[i][1][j+1];
      else
	lst[i][1][j]=v[i][j].se+!(v[i][j].se);
    }
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1)+1)){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p<0 || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1)+1)){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];
vector<int> lst[N][2];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    int t=0;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi==v[i][t].fi && v[i][j].se>v[i][t].se) v[i][t]=v[i][j];
      else if(v[i][j].se>v[i][t].se) v[i][++t]=v[i][j];
    v[i].resize(t+1);
    lst[i][0].resize(v[i].size());
    lst[i][1].resize(v[i].size());
    lst[i][0][v[i].size()-1]=v[i].rbegin()->se-(v[i].rbegin()->se&1);
    lst[i][1][v[i].size()-1]=v[i].rbegin()->se-!(v[i].rbegin()->se&1);
    for(int j=v[i].size()-2;j>=0;j--){
      if(v[i][j].se-(v[i][j].se&1)>=v[i][j+1].fi)
	lst[i][0][j]=lst[i][0][j+1];
      else
	lst[i][0][j]=v[i][j].se-(v[i][j].se&1);
      if(v[i][j].se-!(v[i][j].se)>=v[i][j+1].fi)
	lst[i][1][j]=lst[i][1][j+1];
      else
	lst[i][1][j]=v[i][j].se-!(v[i][j].se);
    }
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p>=v[x>>1].size() || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p>=v[x>>1].size() || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];
vector<int> lst[N][2];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    lst[i][0].resize(v[i].size());
    lst[i][1].resize(v[i].size());
    lst[i][0][v[i].size()-1]=v[i].rbegin()->se-(v[i].rbegin()->se&1);
    lst[i][1][v[i].size()-1]=v[i].rbegin()->se-!(v[i].rbegin()->se&1);
    for(int j=v[i].size()-2;j>=0;j--){
      if(v[i][j].se-(v[i][j].se&1)>=v[i][j+1].fi)
	lst[i][0][j]=lst[i][0][j+1];
      else
	lst[i][0][j]=v[i][j].se-(v[i][j].se&1);
      if(v[i][j].se-!(v[i][j].se)>=v[i][j+1].fi)
	lst[i][1][j]=lst[i][1][j+1];
      else
	lst[i][1][j]=v[i][j].se-!(v[i][j].se);
    }
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p>=v[x>>1].size() || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int p=lower_bound(v[x>>1].begin(),v[x>>1].end(),par(y,inf))-v[x>>1].begin()-1,L;
	if(p>=v[x>>1].size() || v[x>>1][p].fi>y) L=-1;
	else L=lst[x>>1][x&1][p];
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],mst[N],lst[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) mst[i]=inf;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    lst[x]=max(lst[x],r); lst[y]=max(lst[y],r);
    mst[x]=min(mst[x],l); mst[y]=min(mst[y],l);
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int L=lst[x>>1]-!(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1));
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int L=lst[x>>1]-(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1));
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],mst[N],lst[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) mst[i]=inf;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    mst[i]=v[i][0].fi; lst[i]=v[i][0].se;
    int mx=v[i][0].se+1;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi<=mx) lst[i]=v[i][j].se,mx=max(mx,v[i][j].se+1);
      else break;
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int L=lst[x>>1]-!(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int L=lst[x>>1]-(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],mst[N],lst[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) mst[i]=inf;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    lst[x]=max(lst[x],r); lst[y]=max(lst[y],r);
    mst[x]=min(mst[x],l); mst[y]=min(mst[y],l);
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int L=lst[x>>1]-!(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int L=lst[x>>1]-(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> par;

const int N=1000010,inf=(1<<30)-1;

int n,m,cnt,G[N],mst[N],lst[N],dis[N];
struct edge{
  int t,nx,l,r;
}E[N<<1];

priority_queue<par> Q;
vector<par> v[N];

inline void addedge(int x,int y,int l,int r){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].l=l; E[cnt].r=r; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].l=l; E[cnt].r=r; G[y]=cnt;
}

int main(){
#ifdef ljn
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
#endif
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) mst[i]=inf;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r),addedge(x,y,l,--r);
    v[x].push_back(par(l,r));
    v[y].push_back(par(l,r));
  }
  for(int i=1;i<=n;i++){
    if(v[i].empty()) continue;
    sort(v[i].begin(),v[i].end());
    mst[i]=v[i][0].fi; lst[i]=v[i][0].se;
    for(int j=1;j<v[i].size();j++)
      if(v[i][j].fi<=v[i][j-1].se) lst[i]=v[i][j].se;
      else break;
  }
  for(int i=1;i<=(n<<1|1);i++) dis[i]=inf;
  dis[2]=0; Q.push(par(dis[2],2));
  while(!Q.empty()){
    int x=Q.top().se,y=-Q.top().fi; Q.pop();
    if(y!=dis[x]) continue;
    for(int i=G[x>>1];i;i=E[i].nx){
      if(x&1){
	int L=lst[x>>1]-!(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1]>max(y+1,E[i].l+!(E[i].l&1))){
	  dis[E[i].t<<1]=max(y+1,E[i].l+!(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1],E[i].t<<1));
	}
      }
      else{
	int L=lst[x>>1]-(lst[x>>1]&1);
	if(y<mst[x>>1]) L=-1;
	if(E[i].l>L || E[i].r<dis[x]) continue;
	if(dis[E[i].t<<1|1]>max(y+1,E[i].l+(E[i].l&1))){
	  dis[E[i].t<<1|1]=max(y+1,E[i].l+(E[i].l&1)+1);
	  Q.push(par(-dis[E[i].t<<1|1],E[i].t<<1|1));
	}
      }
    }
  }
  int ans=min(dis[n<<1],dis[n<<1|1]);
  if(ans==inf) puts("-1");
  else printf("%d\n",ans);
  return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
typedef pair<int,int> pii;
const int inf=2e9;

int gi() {
	int x=0,o=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') o=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*o;
}

int n,m,p[N][2];
vector<pii> G[N][2];
vector<int> f[N][2];

struct data {
	int d,u,t,e;
	bool operator<(const data &A) const {
		return d>A.d;
	}
};
struct edge { int v,l,r,o; };

vector<edge> E[N];

int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	cin>>n>>m;
	for(int i=1,u,v,l,r;i<=m;i++) u=gi(),v=gi(),l=gi(),r=gi(),E[u].pb((edge){v,l,r,sz(E[v])}),E[v].pb((edge){u,l,r,sz(E[u])-1});
	for(int i=1;i<=n;i++)
		for(int j=0;j<2;j++) {
			f[i][j].resize(sz(E[i]),inf);
			G[i][j].resize(sz(E[i]));
			for(int k=0;k<sz(E[i]);k++) G[i][j][k]=mp(E[i][k].l+((E[i][k].l&1)^j),k);
			sort(G[i][j].begin(),G[i][j].end());
		}
	priority_queue<data> Q;
	for(int i=0;i<sz(E[1]);i++)
		if(!E[1][i].l) f[1][0][i]=0,Q.push((data){0,1,0,i});
	while(!Q.empty()) {
		data x=Q.top();Q.pop();
		int u=x.u,t=x.t,e=x.e,re=E[u][e].o,v=E[u][e].v,d=f[u][t][e],r=E[u][e].r-((E[u][e].r&1)^t);
		if(x.d>d) continue;
		if(f[v][t^1][re]>d+1&&E[v][re].l<=d+1&&E[v][re].r>=d+1) f[v][t^1][re]=d+1,Q.push((data){d+1,v,t^1,re});
		if(d>r) continue;
		while(p[u][t]<sz(E[u])) {
			pii g=G[u][t][p[u][t]];
			if(g.fi>r) break;
			if(f[u][t][g.se]>max(g.fi,d)) f[u][t][g.se]=max(g.fi,d),Q.push((data){max(g.fi,d),u,t,g.se});
			++p[u][t];
		}
	}
	int ans=inf;
	for(int i=0;i<sz(E[n]);i++)
		for(int j=0;j<2;j++) ans=min(ans,f[n][j][i]);
	if(ans==inf) ans=-1;
	cout<<ans;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
typedef pair<int,int> pii;
const int inf=2e9;

int gi() {
	int x=0,o=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') o=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*o;
}

int n,m,p[N][2];
vector<pii> G[N][2];
vector<int> f[N][2];

struct data {
	int d,u,t,e;
	bool operator<(const data &A) const {
		return d>A.d;
	}
};
struct edge { int v,l,r,o; };

vector<edge> E[N];

int main() {
	cin>>n>>m;
	for(int i=1,u,v,l,r;i<=m;i++) u=gi(),v=gi(),l=gi(),r=gi(),E[u].pb((edge){v,l,r,sz(E[v])}),E[v].pb((edge){v,l,r,sz(E[u])-1});
	for(int i=1;i<=n;i++)
		for(int j=0;j<2;j++) {
			f[i][j].resize(sz(E[i]),inf);
			G[i][j].resize(sz(E[i]));
			for(int k=0;k<sz(E[i]);k++) G[i][j][k]=mp(E[i][k].l+((E[i][k].l&1)^j),k);
			sort(G[i][j].begin(),G[i][j].end());
		}
	priority_queue<data> Q;
	for(int i=0;i<sz(E[1]);i++)
		if(!E[1][i].l) f[1][0][i]=0,Q.push((data){0,1,0,i});
	while(!Q.empty()) {
		data x=Q.top();Q.pop();
		int u=x.u,t=x.t,e=x.e,re=E[u][e].o,v=E[u][e].v,d=f[u][t][e],r=E[u][e].r-((E[u][e].r&1)^t);
		if(x.d>d) continue;
		if(f[v][t^1][re]>d+1&&E[v][re].l<=d+1&&E[v][re].r>=d+1) f[v][t^1][re]=d+1,Q.push((data){d+1,v,t^1,re});
		while(p[u][t]<sz(E[u])) {
			pii g=G[u][t][p[u][t]];
			if(g.fi>r) break;
			if(f[u][t][g.se]>max(g.fi,d)) f[u][t][g.se]=max(g.fi,d),Q.push((data){max(g.fi,d),u,t,g.se});
			++p[u][t];
		}
	}
	int ans=inf;
	for(int i=0;i<sz(E[n]);i++)
		for(int j=0;j<2;j++) ans=min(ans,f[n][j][i]);
	if(ans==inf) ans=-1;
	cout<<ans;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
typedef pair<int,int> pii;
const int inf=2e9;

int gi() {
	int x=0,o=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') o=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*o;
}

int n,m,p[N][2];
vector<pii> G[N][2];
vector<int> f[N][2];

struct data {
	int d,u,t,e;
	bool operator<(const data &A) const {
		return d>A.d;
	}
};
struct edge { int v,l,r,o; };

vector<edge> E[N];

int main() {
	cin>>n>>m;
	if(n==1) return puts("0"),0;
	for(int i=1,u,v,l,r;i<=m;i++) u=gi(),v=gi(),l=gi(),r=gi(),E[u].pb((edge){v,l,r,sz(E[v])}),E[v].pb((edge){u,l,r,sz(E[u])-1});
	for(int i=1;i<=n;i++)
		for(int j=0;j<2;j++) {
			f[i][j].resize(sz(E[i]),inf);
			G[i][j].resize(sz(E[i]));
			for(int k=0;k<sz(E[i]);k++) G[i][j][k]=mp(E[i][k].l+((E[i][k].l&1)^j),k);
			sort(G[i][j].begin(),G[i][j].end());
		}
	priority_queue<data> Q;
	for(int i=0;i<sz(E[1]);i++)
		if(!E[1][i].l) f[1][0][i]=0,Q.push((data){0,1,0,i});
	while(!Q.empty()) {
		data x=Q.top();Q.pop();
		int u=x.u,t=x.t,e=x.e,re=E[u][e].o,v=E[u][e].v,d=f[u][t][e],r=E[u][e].r-((E[u][e].r&1)^t);
		if(x.d>d) continue;
		if(f[v][t^1][re]>d+1&&E[v][re].l<=d+1&&E[v][re].r>=d+1) f[v][t^1][re]=d+1,Q.push((data){d+1,v,t^1,re});
		if(d>r) continue;
		while(p[u][t]<sz(E[u])) {
			pii g=G[u][t][p[u][t]];
			if(g.fi>r) break;
			if(f[u][t][g.se]>max(g.fi,d)) f[u][t][g.se]=max(g.fi,d),Q.push((data){max(g.fi,d),u,t,g.se});
			++p[u][t];
		}
	}
	int ans=inf;
	for(int i=0;i<sz(E[n]);i++)
		for(int j=0;j<2;j++) ans=min(ans,f[n][j][i]);
	if(ans==inf) ans=-1;
	cout<<ans;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define PB push_back
#define ZERO (1e-10)
#define INF int(1e9+1)
#define CL(A,I) (memset(A,I,sizeof(A)))
#define DEB printf("DEB!\n");
#define D(X) cout<<"  "<<#X": "<<X<<endl;
#define EQ(A,B) (A+ZERO>B&&A-ZERO<B)
typedef long long ll;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef vector<ii> vii;
#define IN(n) int n;scanf("%d",&n);
#define FOR(i, m, n) for (int i(m); i < n; i++)
#define F(n) FOR(i,0,n)
#define FF(n) FOR(j,0,n)
#define FT(m, n) FOR(k, m, n)
#define aa first
#define bb second
void ga(int N,int *A){F(N)scanf("%d",A+i);}
#define MX (1<<20)
struct eg{
    int a,l,r;
    bool operator<(const eg&r)const{return l>r.l;}
}h;
vector<eg> g[MX][2];
int N,M,a,b,c,d,B,J;
priority_queue<ii> Q;
int dj(){
    Q.push({0,0});
    while(!Q.empty()){
        B=a=-Q.top().aa,b=Q.top().bb,Q.pop(),J=a&1;
        if(b+1==N)return a;
        while(!g[b][J].empty()&&g[b][J].back().l<=B){
            h=g[b][J].back(),g[b][J].pop_back(),B=max(B,h.r);
            if(B%2!=J)--B;
            if(h.r<a)continue;
            d=max(h.l,a);
            if(d%2!=J)++d;
            if(d+1<=h.r&&d>=h.l)Q.push({-d-1,h.a});
        }
    }
    return -1;
}
int main(void){
    scanf("%d%d",&N,&M);
    F(M){
        scanf("%d%d%d%d",&a,&b,&c,&d),--a,--b;
        FF(2)g[a][j].PB({b,c,d}),g[b][j].PB({a,c,d});
    }
    F(N)FF(2)sort(g[i][j].begin(),g[i][j].end());
    printf("%d\n",dj());
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N = (int)5e5 + 5;

struct Edge {
  int v, l, r;

  Edge() {}
  Edge(const int& _v, const int& _l, const int& _r)
    : v(_v), l(_l), r(_r) {}

  bool operator < (const Edge& other) const {
    if (l != other.l)
      return l < other.l;
    return r < other.r;
  }
};

vector <vector <Edge> > es;
vector <int> now;

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(NULL);

  int n, m, a, b, l, r;
  cin >> n >> m;
  es.resize(n + n + 1);
  now.resize(n + n + 1);
  for (int i = 0; i < m; ++i) {
    cin >> a >> b >> l >> r;
    if (l & 1) {
      if (r & 1) {
        es[a].emplace_back(b + n, l + 1, r - 1);
        es[b].emplace_back(a + n, l + 1, r - 1);
        es[a + n].emplace_back(b, l, r - 2);
        es[b + n].emplace_back(a, l, r - 2);
      } else {
        if (l + 1 < r) {
          es[a].emplace_back(b + n, l + 1, r - 2);
          es[b].emplace_back(a + n, l + 1, r - 2);
        }
        es[a + n].emplace_back(b, l, r - 1);
        es[b + n].emplace_back(a, l, r - 1);
      }
    } else {
      if (r & 1) {
        es[a].emplace_back(b + n, l, r - 1);
        es[b].emplace_back(a + n, l, r - 1);
        if (l + 1 < r) {
          es[a + n].emplace_back(b, l + 1, r - 2);
          es[b + n].emplace_back(a, l + 1, r - 2);
        }
      } else {
        es[a].emplace_back(b + n, l, r - 2);
        es[b].emplace_back(a + n, l, r - 2);
        es[a + n].emplace_back(b, l + 1, r - 1);
        es[b + n].emplace_back(a, l + 1, r - 1);
      }
    }
  }
  for (int i = 1; i <= n + n; ++i)
    sort(es[i].begin(), es[i].end());
  priority_queue <tuple <int, int, int>, vector <tuple <int, int, int> >, greater<tuple <int, int, int> > > q;
  q.emplace(0, 0, 1);
  int ans = 0x7f7f7f7f;
  while (!q.empty()) {
    int u, b, e;
    tie(b, e, u) = q.top();
    q.pop();
    // cout << u << '\n';
    if (u == n || u == n + n)
      ans = min(ans, b);
    for (int& i = now[u]; i < (int)es[u].size(); ++i) {
      if (e < es[u][i].l)
        break;
      if (b <= es[u][i].r)
        q.emplace(max(b + 1, es[u][i].l + 1), es[u][i].r + 1, es[u][i].v);
    }
  }
  cout << (ans == 0x7f7f7f7f ? -1 : ans) << '\n';
  return 0;
}


#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <assert.h>
#include <algorithm>
#include <iomanip>
#include <time.h>
#include <math.h>
#include <bitset>

#pragma comment(linker, "/STACK:256000000")

using namespace std;

typedef long long int ll;
typedef long double ld;

/** Interface */

inline int readChar();
template <class T = int> inline T readInt();
template <class T> inline void writeInt(T x);
inline void writeChar(int x);
inline void writeWord(const char *s);
inline void flush();

/** Read */

static const int buf_size = 4096;

inline int getChar()
{
	static char buf[buf_size];
	static int len = 0, pos = 0;
	if (pos == len)
		pos = 0, len = fread(buf, 1, buf_size, stdin);
	if (pos == len)
		return -1;
	return buf[pos++];
}

inline int readChar()
{
	int c = getChar();
	while (c <= 32)
		c = getChar();
	return c;
}

template <class T>
inline T readInt()
{
	int s = 1, c = readChar();
	T x = 0;
	if (c == '-')
		s = -1, c = getChar();
	while ('0' <= c && c <= '9')
		x = x * 10 + c - '0', c = getChar();
	return s == 1 ? x : -x;
}

/** Write */

static int write_pos = 0;
static char write_buf[buf_size];

inline void writeChar(int x)
{
	if (write_pos == buf_size)
		fwrite(write_buf, 1, buf_size, stdout), write_pos = 0;
	write_buf[write_pos++] = x;
}

inline void flush()
{
	if (write_pos)
		fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
}

template <class T>
inline void writeInt(T x)
{
	if (x < 0)
		writeChar('-'), x = -x;

	char s[24];
	int n = 0;
	while (x || !n)
		s[n++] = '0' + x % 10, x /= 10;
	while (n--)
		writeChar(s[n]);
}

inline void writeWord(const char *s)
{
	while (*s)
		writeChar(*s++);
}

const int INF = 1000 * 1000 * 1000 + 21;
const ll LLINF = (1ll << 60) + 5;
const int MOD = 1000 * 1000 * 1000 + 7;

const int MAX_N = 500 * 1000 + 228;

struct edge
{
	int v;
	int u;
	ll l;
	ll r;
	int num;
	int v_type;
};

int n, m;
vector<edge> graph[MAX_N][2];
int ptr[MAX_N][2];
edge edges[2 * MAX_N];
ll dist[2 * MAX_N];
set<pair<ll, int>> look_now;

bool cmp(const edge &a, const edge &b)
{
	return a.l < b.l || (a.l == b.l && a.r < b.r);
}

int main()
{
#ifdef CH_EGOR
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("", "r", stdin);
	//freopen("", "w", stdout);
#endif

	n = readInt();
	m = readInt();

	for (int i = 0; i < m; ++i)
	{
		edges[i].v = readInt() - 1;
		edges[i].u = readInt() - 1;
		edges[i].l = readInt();
		edges[i].r = readInt();
		edges[i].num = i;
		edges[i].v_type = 0;

		edges[i + m] = edges[i];
		edges[i + m].num = i + m;
		edges[i + m].v_type = 1;

		graph[edges[i].v][0].push_back(edges[i]);
		graph[edges[i].u][1].push_back(edges[i]);

		graph[edges[i + m].v][1].push_back(edges[i + m]);
		graph[edges[i + m].u][0].push_back(edges[i + m]);
	}

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < 2; ++j)
		{
			sort(graph[i][j].begin(), graph[i][j].end(), cmp);
		}
	}

	for (int i = 0; i < 2 * m; ++i)
	{
		dist[i] = LLINF;
	}

	memset(ptr, 0, sizeof(ptr));

	while (ptr[0][0] < (int)graph[0][0].size() && graph[0][0][ptr[0][0]].l == 0)
	{
		dist[graph[0][0][ptr[0][0]].num] = 0;
		look_now.insert({0ll, graph[0][0][ptr[0][0]].num});
		++ptr[0][0];
	}

	//cout << look_now.size() << endl;

	while (!look_now.empty())
	{
		int now = look_now.begin()->second;
		look_now.erase(look_now.begin());

		ll cur_r = edges[now].r;
		int v = edges[now].v;
		int type = edges[now].v_type;

		if ((cur_r&1) != type) --cur_r;
		while (ptr[v][type] < (int)graph[v][type].size() &&
			   graph[v][type][ptr[v][type]].l <= cur_r)
		{
			ll min_can = LLINF;
			if (graph[v][type][ptr[v][type]].l > dist[now] + 1)
			{
				if ((graph[v][type][ptr[v][type]].l&1) != type)
				{
					min_can = graph[v][type][ptr[v][type]].l + 1;
				}
				else
				{
					min_can = graph[v][type][ptr[v][type]].l;
				}
			}
			else
			{
				if ((dist[now]&1) != type)
					min_can = dist[now] + 1;
				else
					min_can = dist[now] + 2;
			}
	//		cout << "KEK" << endl;
	//		cout << min_can << endl;
	//		cout << graph[v][type][ptr[v][type]].r << endl;
			if (min_can < graph[v][type][ptr[v][type]].r && min_can < dist[graph[v][type][ptr[v][type]].num])
			{
				look_now.erase({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
				dist[graph[v][type][ptr[v][type]].num] = min_can;
				look_now.insert({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
			}

			++ptr[v][type];
		}

		cur_r = edges[now].r;
		v = edges[now].u;
		type ^= 1;

		if ((cur_r&1) != type) --cur_r;
		while (ptr[v][type] < (int)graph[v][type].size() &&
			   graph[v][type][ptr[v][type]].l <= cur_r)
		{
			ll min_can = LLINF;
			if (graph[v][type][ptr[v][type]].l > dist[now] + 1)
			{
				if ((graph[v][type][ptr[v][type]].l&1) != type)
				{
					min_can = graph[v][type][ptr[v][type]].l + 1;
				}
				else
				{
					min_can = graph[v][type][ptr[v][type]].l;
				}
			}
			else
			{
				if ((dist[now]&1) != type)
					min_can = dist[now] + 1;
				else
					min_can = dist[now] + 2;
			}

			if (min_can < graph[v][type][ptr[v][type]].r && min_can < dist[graph[v][type][ptr[v][type]].num])
			{
				look_now.erase({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
				dist[graph[v][type][ptr[v][type]].num] = min_can;
				look_now.insert({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
			}

			++ptr[v][type];
		}
	}

	ll ans = LLINF;
	for (int i = 0; i < 2 * m; ++i)
	{
		if (edges[i].v == n - 1)
		{
			if ((dist[i]&1) == edges[i].v_type)
				ans = min(ans, dist[i]);
			else
				ans = min(ans, dist[i] + 1);
		}
		if (edges[i].u == n - 1)
		{
			if ((dist[i]&1) == edges[i].v_type)
				ans = min(ans, dist[i] + 1);
			else
				ans = min(ans, dist[i]);
		}
	}

	if (n == 1)
	{
		ans = 0;
	}

	if (ans >= LLINF)
	{
		writeInt(-1);
	}
	else
	{
		writeInt(ans);
	}

	flush();

	return 0;
}


#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <assert.h>
#include <algorithm>
#include <iomanip>
#include <time.h>
#include <math.h>
#include <bitset>

#pragma comment(linker, "/STACK:256000000")

using namespace std;

typedef long long int ll;
typedef long double ld;

/** Interface */

inline int readChar();
template <class T = int> inline T readInt();
template <class T> inline void writeInt(T x);
inline void writeChar(int x);
inline void writeWord(const char *s);
inline void flush();

/** Read */

static const int buf_size = 4096;

inline int getChar()
{
	static char buf[buf_size];
	static int len = 0, pos = 0;
	if (pos == len)
		pos = 0, len = fread(buf, 1, buf_size, stdin);
	if (pos == len)
		return -1;
	return buf[pos++];
}

inline int readChar()
{
	int c = getChar();
	while (c <= 32)
		c = getChar();
	return c;
}

template <class T>
inline T readInt()
{
	int s = 1, c = readChar();
	T x = 0;
	if (c == '-')
		s = -1, c = getChar();
	while ('0' <= c && c <= '9')
		x = x * 10 + c - '0', c = getChar();
	return s == 1 ? x : -x;
}

/** Write */

static int write_pos = 0;
static char write_buf[buf_size];

inline void writeChar(int x)
{
	if (write_pos == buf_size)
		fwrite(write_buf, 1, buf_size, stdout), write_pos = 0;
	write_buf[write_pos++] = x;
}

inline void flush()
{
	if (write_pos)
		fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
}

template <class T>
inline void writeInt(T x)
{
	if (x < 0)
		writeChar('-'), x = -x;

	char s[24];
	int n = 0;
	while (x || !n)
		s[n++] = '0' + x % 10, x /= 10;
	while (n--)
		writeChar(s[n]);
}

inline void writeWord(const char *s)
{
	while (*s)
		writeChar(*s++);
}

const int INF = 1000 * 1000 * 1000 + 21;
const ll LLINF = (1ll << 60) + 5;
const int MOD = 1000 * 1000 * 1000 + 7;

const int MAX_N = 500 * 1000 + 228;

struct edge
{
	int v;
	int u;
	ll l;
	ll r;
	int num;
	int v_type;
};

int n, m;
vector<edge> graph[MAX_N][2];
int ptr[MAX_N][2];
edge edges[2 * MAX_N];
ll dist[2 * MAX_N];
set<pair<ll, int>> look_now;

bool cmp(const edge &a, const edge &b)
{
	return a.l < b.l || (a.l == b.l && a.r < b.r);
}

int main()
{
#ifdef CH_EGOR
	freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#else
	//freopen("", "r", stdin);
	//freopen("", "w", stdout);
#endif

	n = readInt();
	m = readInt();

	for (int i = 0; i < m; ++i)
	{
		edges[i].v = readInt() - 1;
		edges[i].u = readInt() - 1;
		edges[i].l = readInt();
		edges[i].r = readInt();
		edges[i].num = i;
		edges[i].v_type = 0;

		edges[i + m] = edges[i];
		edges[i + m].num = i + m;
		edges[i + m].v_type = 1;

		graph[edges[i].v][0].push_back(edges[i]);
		graph[edges[i].u][1].push_back(edges[i]);

		graph[edges[i + m].v][1].push_back(edges[i + m]);
		graph[edges[i + m].u][0].push_back(edges[i + m]);
	}

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < 2; ++j)
		{
			sort(graph[i][j].begin(), graph[i][j].end(), cmp);
		}
	}

	for (int i = 0; i < 2 * m; ++i)
	{
		dist[i] = LLINF;
	}

	memset(ptr, 0, sizeof(ptr));

	while (ptr[0][0] < (int)graph[0][0].size() && graph[0][0][ptr[0][0]].l == 0)
	{
		dist[graph[0][0][ptr[0][0]].num] = 0;
		look_now.insert({0ll, graph[0][0][ptr[0][0]].num});
		++ptr[0][0];
	}

	//cout << look_now.size() << endl;

	while (!look_now.empty())
	{
		int now = look_now.begin()->second;
		look_now.erase(look_now.begin());

		ll cur_r = edges[now].r;
		int v = edges[now].v;
		int type = edges[now].v_type;

		if ((cur_r&1) != type) --cur_r;
		while (ptr[v][type] < (int)graph[v][type].size() &&
			   graph[v][type][ptr[v][type]].l <= cur_r)
		{
			ll min_can = LLINF;
			if (graph[v][type][ptr[v][type]].l > dist[now] + 1)
			{
				if ((graph[v][type][ptr[v][type]].l&1) != type)
				{
					min_can = graph[v][type][ptr[v][type]].l + 1;
				}
				else
				{
					min_can = graph[v][type][ptr[v][type]].l;
				}
			}
			else
			{
				if ((dist[now]&1) != type)
					min_can = dist[now] + 1;
				else
					min_can = dist[now] + 2;
			}
	//		cout << "KEK" << endl;
	//		cout << min_can << endl;
	//		cout << graph[v][type][ptr[v][type]].r << endl;
			if (min_can < graph[v][type][ptr[v][type]].r && min_can < dist[graph[v][type][ptr[v][type]].num])
			{
				look_now.erase({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
				dist[graph[v][type][ptr[v][type]].num] = min_can;
				look_now.insert({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
			}

			++ptr[v][type];
		}

		cur_r = edges[now].r;
		v = edges[now].u;
		type ^= 1;

		if ((cur_r&1) != type) --cur_r;
		while (ptr[v][type] < (int)graph[v][type].size() &&
			   graph[v][type][ptr[v][type]].l <= cur_r)
		{
			ll min_can = LLINF;
			if (graph[v][type][ptr[v][type]].l > dist[now] + 1)
			{
				if ((graph[v][type][ptr[v][type]].l&1) != type)
				{
					min_can = graph[v][type][ptr[v][type]].l + 1;
				}
				else
				{
					min_can = graph[v][type][ptr[v][type]].l;
				}
			}
			else
			{
				if ((dist[now]&1) != type)
					min_can = dist[now] + 1;
				else
					min_can = dist[now] + 2;
			}

			if (min_can < graph[v][type][ptr[v][type]].r && min_can < dist[graph[v][type][ptr[v][type]].num])
			{
				look_now.erase({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
				dist[graph[v][type][ptr[v][type]].num] = min_can;
				look_now.insert({dist[graph[v][type][ptr[v][type]].num], graph[v][type][ptr[v][type]].num});
			}

			++ptr[v][type];
		}
	}

	ll ans = LLINF;
	for (int i = 0; i < 2 * m; ++i)
	{
		if (edges[i].v == n - 1)
		{
			if ((dist[i]&1) == edges[i].v_type)
				ans = min(ans, dist[i]);
			else
				ans = min(ans, dist[i] + 1);
		}
		if (edges[i].u == n - 1)
		{
			if ((dist[i]&1) == edges[i].v_type)
				ans = min(ans, dist[i] + 1);
			else
				ans = min(ans, dist[i]);
		}
	}

	if (ans >= LLINF)
	{
		writeInt(-1);
	}
	else
	{
		writeInt(ans);
	}

	flush();

	return 0;
}


#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair < int, int > pii;

inline int Read()
{
	int x = 0, f = 1, c = getchar();
	for (; !isdigit(c); c = getchar())
		if (c == '-')
			f = -1;
	for (;  isdigit(c); c = getchar())
		x = x * 10 + c - '0';
	return x * f;
}

const int MAXN = 500005;
const int INF = 0x3f3f3f3f;

struct Node { int v, x, t, i; bool operator < (const Node &b) const { return v > b.v; } };
struct Edge { int p, l, r, v; };
int n, m, cur[MAXN][2];
vector < Edge > G[MAXN];
vector < pii > adj[MAXN][2];
vector < int > f[MAXN][2];
priority_queue < Node > Q;

int main()
{
#ifdef wxh010910
	freopen("data.in", "r", stdin);
#endif
	n = Read(), m = Read();
	if (n == 1)
		return puts("0"), 0;
	for (int i = 1, u, v, l, r; i <= m; i ++)
		u = Read(), v = Read(), l = Read(), r = Read(), G[u].pb({v, l, r, G[v].size()}), G[v].pb({u, l, r, G[u].size() - 1});
	for (int i = 1; i <= n; i ++)
		for (int j = 0; j < 2; j ++)
		{
			f[i][j].resize(G[i].size(), INF);
			for (int k = 0; k < G[i].size(); k ++)
				adj[i][j].pb(mp(G[i][k].l + ((G[i][k].l & 1) ^ j), k));
			sort(adj[i][j].begin(), adj[i][j].end());
		}
	for (int i = 0; i < G[1].size(); i ++)
		if (!G[1][i].l)
			f[1][0][i] = 0, Q.push({0, 1, 0, i});
	/*
	for (int i = 1; i <= n; i ++)
		for (int j = 0; j < G[i].size(); j ++)
			printf("edge[%d][%d].p = %d\n", i, j, G[i][j].p);
	*/
	while (!Q.empty())
	{
		Node tmp = Q.top(); Q.pop();
		int x = tmp.x, t = tmp.t, p = tmp.i, r = G[x][p].v, y = G[x][p].p, v = f[x][t][p], d = G[x][p].r - ((G[x][p].r & 1) ^ t);
		if (tmp.v > v)
			continue;
		//printf("%d %d %d %d\n", x, t, p, v);
		if (f[y][t ^ 1][r] > v + 1 && G[x][p].l <= v + 1 && G[x][p].r >= v + 1)
			f[y][t ^ 1][r] = v + 1, Q.push({v + 1, y, t ^ 1, r});
		if (v > d)
			continue;
		while (cur[x][t] < G[x].size())
		{
			pii g = adj[x][t][cur[x][t]];
			if (g.xx > d)
				break;
			if (max(g.xx, v) < f[x][t][g.yy])
				f[x][t][g.yy] = max(g.xx, v), Q.push({max(g.xx, v), x, t, g.yy});
			cur[x][t] ++;
		}
	}
	int ans = INF;
	for (int i = 0; i < G[n].size(); i ++)
		for (int j = 0; j < 2; j ++)
			ans = min(ans, f[n][j][i]);
	if (ans == INF)
		ans = -1;
	return printf("%d\n", ans), 0;
}


#ifdef DEBUG
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cassert>
#include <sstream>
#include <fstream>
#include <functional>
#include <set>
#include <bitset>
#include <string>
#include <utility>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#else
#include <bits/stdc++.h>
#endif

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#define rep(i, n) for (int i = 0, i##_end_ = (n); i < i##_end_; ++i)
#define per(i, n) for (int i = (n) - 1; i >= 0; --i)
#define forn(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define nrof(i, r, l) for (int i = (r), i##_end_ = (l); i >= i##_end_; --i)
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define SZ(x) (int)((x).size())
#define ALL(x) (x).begin(), (x).end()

using namespace std;

typedef vector<int> vi;

typedef pair<int, int> pii;

typedef long long LL;

template<typename T> inline bool chkmax(T &x, const T &y) {
	return x < y ? x = y, 1 : 0;
}

template<typename T> inline bool chkmin(T &x, const T &y) {
	return x > y ? x = y, 1 : 0;
}

#ifdef DEBUG
char *input_file, *output_file;
#endif

struct IO {
	static const int maxn = (1 << 25) + 10;

	char a[maxn], *s, b[maxn], *t;

	void INPUT() {
		s = a;
		t = b;
		#ifdef DEBUG
		FILE *f = fopen(input_file, "r");
		a[fread(a, 1, sizeof a, f)] = 0;
		#else
		a[fread(a, 1, sizeof a, stdin)] = 0;
		#endif
	}

	void OUTPUT() {
#ifdef DEBUG
		FILE *f = fopen(output_file, "w");
		fwrite(b, 1, t - b, f);
#else
		fwrite(b, 1, t - b, stdout);
#endif
	}

	operator int() {
		int x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator LL() {
		LL x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator char() {
		while(*s <= 32) {
			++s;
		}
		char ret = *s;
		++s;
		return ret;
	}

	inline void out(int x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(int x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(LL x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(LL x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(char c) {
		*t++ = c;
		return;
	}

	inline void out(char *s) {
		while(*s >= ' ') {
			*t++ = *s++;
		}
		return;
	}
}io;

void Main();

int main(int argc, char *argv[]) {
#ifdef DEBUG
	input_file = argv[1];
	output_file = argv[2];
#endif
	io.INPUT();
	Main();
	io.OUTPUT();
	return 0;
}

//---------------------------------------------------------------------------------------head---------------------------------------------------------------------------------------

const int maxn = 5e5 + 100, maxm = 5e5 + 100;

int n, m;
int u[maxm][2], l[maxm], r[maxm], dp[maxm << 1][2];
priority_queue<pii, vector<pii>, greater<pii> > heap;
vi g[maxn];

void Main() {
	n = io;
	m = io;
	memset(dp, 0x3f, sizeof dp);
	rep(i, m) {
		u[i][0] = io;
		u[i][1] = io;
		l[i] = io;
		r[i] = io;
		g[u[i][0]].pb((i << 1) | 1);
		g[u[i][1]].pb(i << 1);
		if(!l[i]) {
			if(u[i][0] == 1) {
				dp[i << 1][0] = 0;
				heap.push(mp(0, i << 1));
			}
			if(u[i][1] == 1) {
				dp[(i << 1) | 1][0] = 0;
				heap.push(mp(0, (i << 1) | 1));
			}
		}
	}
	forn(u, 1, n) {
		sort(ALL(g[u]), [&](int i, int j) {
				return r[i >> 1] < r[j >> 1];
				});
	}
	int ans = 1000000001;
	while(!heap.empty()) {
		int T = heap.top().X, e = heap.top().Y, v = u[e >> 1][e & 1], d = T & 1, lst = T;
		heap.pop();
		if(T != dp[e][d]) {
			continue;
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			if(l <= lst && lst <= r) {
				lst = (r - lst & 1) ? r - 1 : r;
			}
		}
		debug("dp[%d] = %d\n", v, T);
		if(v == n) {
			chkmin(ans, T);
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			debug("\t%d %d\n", l, r);
			if(T >= l && T + 1 <= r) {
				if(chkmin(dp[i][d ^ 1], T + 1)) {
					debug("\t\t%d\n", i);
					heap.push(mp(T + 1, i));
				}
			}
			if(lst >= l && T <= r) {
				int w = max(T, l);
				if(chkmin(dp[i ^ 1][d], w)) {
					debug("\t\t%d\n", i ^ 1);
					heap.push(mp(w, i ^ 1));
				}
			}
		}
	}
	io.out(ans <= 1000000000 ? ans : -1, '\n');
	return;
}


#ifdef DEBUG
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cassert>
#include <sstream>
#include <fstream>
#include <functional>
#include <set>
#include <bitset>
#include <string>
#include <utility>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#else
#include <bits/stdc++.h>
#endif

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#define rep(i, n) for (int i = 0, i##_end_ = (n); i < i##_end_; ++i)
#define per(i, n) for (int i = (n) - 1; i >= 0; --i)
#define forn(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define nrof(i, r, l) for (int i = (r), i##_end_ = (l); i >= i##_end_; --i)
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define SZ(x) (int)((x).size())
#define ALL(x) (x).begin(), (x).end()

using namespace std;

typedef vector<int> vi;

typedef pair<int, int> pii;

typedef long long LL;

template<typename T> inline bool chkmax(T &x, const T &y) {
	return x < y ? x = y, 1 : 0;
}

template<typename T> inline bool chkmin(T &x, const T &y) {
	return x > y ? x = y, 1 : 0;
}

#ifdef DEBUG
char *input_file, *output_file;
#endif

struct IO {
	static const int maxn = (1 << 25) + 10;

	char a[maxn], *s, b[maxn], *t;

	void INPUT() {
		s = a;
		t = b;
		#ifdef DEBUG
		FILE *f = fopen(input_file, "r");
		a[fread(a, 1, sizeof a, f)] = 0;
		#else
		a[fread(a, 1, sizeof a, stdin)] = 0;
		#endif
	}

	void OUTPUT() {
#ifdef DEBUG
		FILE *f = fopen(output_file, "w");
		fwrite(b, 1, t - b, f);
#else
		fwrite(b, 1, t - b, stdout);
#endif
	}

	operator int() {
		int x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator LL() {
		LL x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator char() {
		while(*s <= 32) {
			++s;
		}
		char ret = *s;
		++s;
		return ret;
	}

	inline void out(int x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(int x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(LL x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(LL x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(char c) {
		*t++ = c;
		return;
	}

	inline void out(char *s) {
		while(*s >= ' ') {
			*t++ = *s++;
		}
		return;
	}
}io;

void Main();

int main(int argc, char *argv[]) {
#ifdef DEBUG
	input_file = argv[1];
	output_file = argv[2];
#endif
	io.INPUT();
	Main();
	io.OUTPUT();
	return 0;
}

//---------------------------------------------------------------------------------------head---------------------------------------------------------------------------------------

const int maxn = 5e5 + 100, maxm = 5e5 + 100;

int n, m;
int u[maxm][2], l[maxm], r[maxm], dp[maxm << 1][2];
priority_queue<pii, vector<pii>, greater<pii> > heap;
vi g[maxn];

void Main() {
	n = io;
	m = io;
	if(n == 1) {
		io.out(0, '\n');
		return;
	}
	memset(dp, 0x3f, sizeof dp);
	rep(i, m) {
		u[i][0] = io;
		u[i][1] = io;
		l[i] = io;
		r[i] = io;
		g[u[i][0]].pb((i << 1) | 1);
		g[u[i][1]].pb(i << 1);
		if(!l[i]) {
			if(u[i][0] == 1) {
				dp[i << 1][0] = 0;
				heap.push(mp(0, i << 1));
			}
			if(u[i][1] == 1) {
				dp[(i << 1) | 1][0] = 0;
				heap.push(mp(0, (i << 1) | 1));
			}
		}
	}
	forn(u, 1, n) {
		sort(ALL(g[u]), [&](int i, int j) {
				return r[i >> 1] < r[j >> 1];
				});
	}
	int ans = 1000000001;
	while(!heap.empty()) {
		int T = heap.top().X, e = heap.top().Y, v = u[e >> 1][e & 1], d = T & 1, lst = T;
		heap.pop();
		if(T != dp[e][d]) {
			continue;
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			if(l <= lst && lst <= r) {
				lst = (r - lst & 1) ? r - 1 : r;
			}
		}
		debug("dp[%d] = %d\n", v, T);
		if(v == n) {
			chkmin(ans, T);
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			debug("\t%d %d\n", l, r);
			if(lst >= l && T + 1 <= r) {
				int w = l;
				if(w - T & 1) {
					++w;
				}
				chkmax(w, T);
				if(w <= lst && w + 1 <= r && w >= l) {
					if(chkmin(dp[i][d ^ 1], w + 1)) {
						debug("\t\t%d\n", i);
						heap.push(mp(w + 1, i));
					}
				}
			}
			if(lst >= l && T <= r) {
				int w = max(T, l);
				if(chkmin(dp[i ^ 1][d], w)) {
					debug("\t\t%d\n", i ^ 1);
					heap.push(mp(w, i ^ 1));
				}
			}
		}
	}
	io.out(ans <= 1000000000 ? ans : -1, '\n');
	return;
}


#ifdef DEBUG
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cassert>
#include <sstream>
#include <fstream>
#include <functional>
#include <set>
#include <bitset>
#include <string>
#include <utility>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#else
#include <bits/stdc++.h>
#endif

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#define rep(i, n) for (int i = 0, i##_end_ = (n); i < i##_end_; ++i)
#define per(i, n) for (int i = (n) - 1; i >= 0; --i)
#define forn(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define nrof(i, r, l) for (int i = (r), i##_end_ = (l); i >= i##_end_; --i)
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define SZ(x) (int)((x).size())
#define ALL(x) (x).begin(), (x).end()

using namespace std;

typedef vector<int> vi;

typedef pair<int, int> pii;

typedef long long LL;

template<typename T> inline bool chkmax(T &x, const T &y) {
	return x < y ? x = y, 1 : 0;
}

template<typename T> inline bool chkmin(T &x, const T &y) {
	return x > y ? x = y, 1 : 0;
}

#ifdef DEBUG
char *input_file, *output_file;
#endif

struct IO {
	static const int maxn = (1 << 25) + 10;

	char a[maxn], *s, b[maxn], *t;

	void INPUT() {
		s = a;
		t = b;
		#ifdef DEBUG
		FILE *f = fopen(input_file, "r");
		a[fread(a, 1, sizeof a, f)] = 0;
		#else
		a[fread(a, 1, sizeof a, stdin)] = 0;
		#endif
	}

	void OUTPUT() {
#ifdef DEBUG
		FILE *f = fopen(output_file, "w");
		fwrite(b, 1, t - b, f);
#else
		fwrite(b, 1, t - b, stdout);
#endif
	}

	operator int() {
		int x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator LL() {
		LL x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator char() {
		while(*s <= 32) {
			++s;
		}
		char ret = *s;
		++s;
		return ret;
	}

	inline void out(int x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(int x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(LL x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(LL x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(char c) {
		*t++ = c;
		return;
	}

	inline void out(char *s) {
		while(*s >= ' ') {
			*t++ = *s++;
		}
		return;
	}
}io;

void Main();

int main(int argc, char *argv[]) {
#ifdef DEBUG
	input_file = argv[1];
	output_file = argv[2];
#endif
	io.INPUT();
	Main();
	io.OUTPUT();
	return 0;
}

//---------------------------------------------------------------------------------------head---------------------------------------------------------------------------------------

const int maxn = 5e5 + 100, maxm = 5e5 + 100;

int n, m;
int u[maxm][2], l[maxm], r[maxm], dp[maxm << 1][2], iter[maxn][2];
priority_queue<pii, vector<pii>, greater<pii> > heap;
vi g[maxn];

void Main() {
	n = io;
	m = io;
	if(n == 1) {
		io.out(0, '\n');
		return;
	}
	memset(dp, 0x3f, sizeof dp);
	rep(i, m) {
		u[i][0] = io;
		u[i][1] = io;
		l[i] = io;
		r[i] = io;
		g[u[i][0]].pb((i << 1) | 1);
		g[u[i][1]].pb(i << 1);
		if(!l[i]) {
			if(u[i][0] == 1) {
				dp[i << 1][0] = 0;
				heap.push(mp(0, i << 1));
			}
			if(u[i][1] == 1) {
				dp[(i << 1) | 1][0] = 0;
				heap.push(mp(0, (i << 1) | 1));
			}
		}
	}
	forn(u, 1, n) {
		sort(ALL(g[u]), [&](int i, int j) {
				return l[i >> 1] < l[j >> 1];
				});
	}
	int ans = 1000000001;
	while(!heap.empty()) {
		int T = heap.top().X, e = heap.top().Y, v = u[e >> 1][e & 1], d = T & 1, lst = T;
		heap.pop();
		if(T != dp[e][d]) {
			continue;
		}
		if(v == n) {
			chkmin(ans, T);
		}
		while(iter[v][d] < SZ(g[v])) {
			int i = g[v][iter[v][d]];
			int l = ::l[i >> 1], r = ::r[i >> 1];
			if(lst < l) {
				break;
			}
			++iter[v][d];
			int w = l;
			if(w - T & 1) {
				++w;
			}
			chkmax(w, T);
			if(w + 1 <= r) {
				if(chkmin(dp[i][d ^ 1], w + 1)) {
					heap.push(mp(w + 1, i));
				}
			}
			if(w <= r) {
				if(chkmin(dp[i ^ 1][d], w)) {
					heap.push(mp(w, i ^ 1));
				}
			}
			chkmax(lst, (r - lst & 1) ? r - 1 : r);
		}
	}
	io.out(ans <= 1000000000 ? ans : -1, '\n');
	return;
}


#ifdef DEBUG
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cassert>
#include <sstream>
#include <fstream>
#include <functional>
#include <set>
#include <bitset>
#include <string>
#include <utility>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#else
#include <bits/stdc++.h>
#endif

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#define rep(i, n) for (int i = 0, i##_end_ = (n); i < i##_end_; ++i)
#define per(i, n) for (int i = (n) - 1; i >= 0; --i)
#define forn(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define nrof(i, r, l) for (int i = (r), i##_end_ = (l); i >= i##_end_; --i)
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define SZ(x) (int)((x).size())
#define ALL(x) (x).begin(), (x).end()

using namespace std;

typedef vector<int> vi;

typedef pair<int, int> pii;

typedef long long LL;

template<typename T> inline bool chkmax(T &x, const T &y) {
	return x < y ? x = y, 1 : 0;
}

template<typename T> inline bool chkmin(T &x, const T &y) {
	return x > y ? x = y, 1 : 0;
}

#ifdef DEBUG
char *input_file, *output_file;
#endif

struct IO {
	static const int maxn = (1 << 25) + 10;

	char a[maxn], *s, b[maxn], *t;

	void INPUT() {
		s = a;
		t = b;
		#ifdef DEBUG
		FILE *f = fopen(input_file, "r");
		a[fread(a, 1, sizeof a, f)] = 0;
		#else
		a[fread(a, 1, sizeof a, stdin)] = 0;
		#endif
	}

	void OUTPUT() {
#ifdef DEBUG
		FILE *f = fopen(output_file, "w");
		fwrite(b, 1, t - b, f);
#else
		fwrite(b, 1, t - b, stdout);
#endif
	}

	operator int() {
		int x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator LL() {
		LL x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator char() {
		while(*s <= 32) {
			++s;
		}
		char ret = *s;
		++s;
		return ret;
	}

	inline void out(int x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(int x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(LL x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(LL x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(char c) {
		*t++ = c;
		return;
	}

	inline void out(char *s) {
		while(*s >= ' ') {
			*t++ = *s++;
		}
		return;
	}
}io;

void Main();

int main(int argc, char *argv[]) {
#ifdef DEBUG
	input_file = argv[1];
	output_file = argv[2];
#endif
	io.INPUT();
	Main();
	io.OUTPUT();
	return 0;
}

//---------------------------------------------------------------------------------------head---------------------------------------------------------------------------------------

const int maxn = 5e5 + 100, maxm = 5e5 + 100;

int n, m;
int u[maxm][2], l[maxm], r[maxm], dp[maxm << 1][2];
priority_queue<pii, vector<pii>, greater<pii> > heap;
vi g[maxn];

void Main() {
	n = io;
	m = io;
	if(n == 1) {
		io.out(0, '\n');
		return;
	}
	memset(dp, 0x3f, sizeof dp);
	rep(i, m) {
		u[i][0] = io;
		u[i][1] = io;
		l[i] = io;
		r[i] = io;
		g[u[i][0]].pb((i << 1) | 1);
		g[u[i][1]].pb(i << 1);
		if(!l[i]) {
			if(u[i][0] == 1) {
				dp[i << 1][0] = 0;
				heap.push(mp(0, i << 1));
			}
			if(u[i][1] == 1) {
				dp[(i << 1) | 1][0] = 0;
				heap.push(mp(0, (i << 1) | 1));
			}
		}
	}
	forn(u, 1, n) {
		sort(ALL(g[u]), [&](int i, int j) {
				return r[i >> 1] < r[j >> 1];
				});
	}
	int ans = 1000000001;
	while(!heap.empty()) {
		int T = heap.top().X, e = heap.top().Y, v = u[e >> 1][e & 1], d = T & 1, lst = T;
		heap.pop();
		if(T != dp[e][d]) {
			continue;
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			if(l <= lst && lst <= r) {
				lst = (r - lst & 1) ? r - 1 : r;
			}
		}
		debug("dp[%d] = %d\n", v, T);
		if(v == n) {
			chkmin(ans, T);
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			debug("\t%d %d\n", l, r);
			if(T >= l && T + 1 <= r) {
				if(chkmin(dp[i][d ^ 1], T + 1)) {
					debug("\t\t%d\n", i);
					heap.push(mp(T + 1, i));
				}
			}
			if(lst >= l && T <= r) {
				int w = max(T, l);
				if(chkmin(dp[i ^ 1][d], w)) {
					debug("\t\t%d\n", i ^ 1);
					heap.push(mp(w, i ^ 1));
				}
			}
		}
	}
	io.out(ans <= 1000000000 ? ans : -1, '\n');
	return;
}


#ifdef DEBUG
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <cassert>
#include <sstream>
#include <fstream>
#include <functional>
#include <set>
#include <bitset>
#include <string>
#include <utility>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#else
#include <bits/stdc++.h>
#endif

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#define rep(i, n) for (int i = 0, i##_end_ = (n); i < i##_end_; ++i)
#define per(i, n) for (int i = (n) - 1; i >= 0; --i)
#define forn(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define nrof(i, r, l) for (int i = (r), i##_end_ = (l); i >= i##_end_; --i)
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define SZ(x) (int)((x).size())
#define ALL(x) (x).begin(), (x).end()

using namespace std;

typedef vector<int> vi;

typedef pair<int, int> pii;

typedef long long LL;

template<typename T> inline bool chkmax(T &x, const T &y) {
	return x < y ? x = y, 1 : 0;
}

template<typename T> inline bool chkmin(T &x, const T &y) {
	return x > y ? x = y, 1 : 0;
}

#ifdef DEBUG
char *input_file, *output_file;
#endif

struct IO {
	static const int maxn = (1 << 25) + 10;

	char a[maxn], *s, b[maxn], *t;

	void INPUT() {
		s = a;
		t = b;
		#ifdef DEBUG
		FILE *f = fopen(input_file, "r");
		a[fread(a, 1, sizeof a, f)] = 0;
		#else
		a[fread(a, 1, sizeof a, stdin)] = 0;
		#endif
	}

	void OUTPUT() {
#ifdef DEBUG
		FILE *f = fopen(output_file, "w");
		fwrite(b, 1, t - b, f);
#else
		fwrite(b, 1, t - b, stdout);
#endif
	}

	operator int() {
		int x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator LL() {
		LL x = 0;
		while(*s != '-' && (*s < '0' || *s > '9')) {
			++s;
		}
		bool f = 0;
		if(*s == '-') {
			f = 1;
			++s;
		}
		while(*s >= '0' && *s <= '9') {
			(x *= 10) += *s - '0';
			++s;
		}
		if(f) {
			x = -x;
		}
		return x;
	}

	operator char() {
		while(*s <= 32) {
			++s;
		}
		char ret = *s;
		++s;
		return ret;
	}

	inline void out(int x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(int x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			int y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(LL x) {
		if(!x) {
			*t++ = '0';
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		return;
	}

	inline void out(LL x, char C) {
		if(!x) {
			*t++ = '0';
			*t++ = C;
			return;
		}
		if(x < 0) {
			*t++ = '-';
			x = -x;
		}
		static char c[20], *i;
		i = c;
		while(x) {
			LL y = x / 10;
			*i++ = x - y * 10 + '0';
			x = y;
		}
		while(i != c) {
			*t++ = *--i;
		}
		*t++ = C;
		return;
	}

	inline void out(char c) {
		*t++ = c;
		return;
	}

	inline void out(char *s) {
		while(*s >= ' ') {
			*t++ = *s++;
		}
		return;
	}
}io;

void Main();

int main(int argc, char *argv[]) {
#ifdef DEBUG
	input_file = argv[1];
	output_file = argv[2];
#endif
	io.INPUT();
	Main();
	io.OUTPUT();
	return 0;
}

//---------------------------------------------------------------------------------------head---------------------------------------------------------------------------------------

const int maxn = 5e5 + 100, maxm = 5e5 + 100;

int n, m;
int u[maxm][2], l[maxm], r[maxm], dp[maxm << 1][2];
priority_queue<pii, vector<pii>, greater<pii> > heap;
vi g[maxn];

void Main() {
	n = io;
	m = io;
	if(n == 1) {
		io.out(0, '\n');
		return;
	}
	memset(dp, 0x3f, sizeof dp);
	rep(i, m) {
		u[i][0] = io;
		u[i][1] = io;
		l[i] = io;
		r[i] = io;
		g[u[i][0]].pb((i << 1) | 1);
		g[u[i][1]].pb(i << 1);
		if(!l[i]) {
			if(u[i][0] == 1) {
				dp[i << 1][0] = 0;
				heap.push(mp(0, i << 1));
			}
			if(u[i][1] == 1) {
				dp[(i << 1) | 1][0] = 0;
				heap.push(mp(0, (i << 1) | 1));
			}
		}
	}
	forn(u, 1, n) {
		sort(ALL(g[u]), [&](int i, int j) {
				return r[i >> 1] < r[j >> 1];
				});
	}
	int ans = 1000000001;
	while(!heap.empty()) {
		int T = heap.top().X, e = heap.top().Y, v = u[e >> 1][e & 1], d = T & 1, lst = T;
		heap.pop();
		if(T != dp[e][d]) {
			continue;
		}
		for (int i: g[v]) {
			int l = ::l[i >> 1], r = ::r[i >> 1];
			if(l <= lst && lst <= r) {
				lst = (r - lst & 1) ? r - 1 : r;
			}
		}
		debug("dp[%d] = %d\n", v, T);
		if(v == n) {
			chkmin(ans, T);
		}
		int lb = 0, rb = SZ(g[v]) - 1;
		while(lb <= rb) {
			int mid = lb + rb >> 1, i = g[v][mid];
			if(r[i >> 1] >= T) {
				rb = mid - 1;
			}
			else {
				lb = mid + 1;
			}
		}
		while(lb < SZ(g[v])) {
			int i = g[v][lb++];
			int l = ::l[i >> 1], r = ::r[i >> 1];
			debug("\t%d %d\n", l, r);
			if(lst >= l && T + 1 <= r) {
				int w = l;
				if(w - T & 1) {
					++w;
				}
				chkmax(w, T);
				if(w <= lst && w + 1 <= r && w >= l) {
					if(chkmin(dp[i][d ^ 1], w + 1)) {
						debug("\t\t%d\n", i);
						heap.push(mp(w + 1, i));
					}
				}
			}
			if(lst >= l && T <= r) {
				int w = max(T, l);
				if(chkmin(dp[i ^ 1][d], w)) {
					debug("\t\t%d\n", i ^ 1);
					heap.push(mp(w, i ^ 1));
				}
			}
		}
	}
	io.out(ans <= 1000000000 ? ans : -1, '\n');
	return;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int _=1e2;
const int maxn=5e5+_;
inline int read()
{
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}

struct edge{int x,y,l,r;edge(){}edge(int X,int Y,int L,int R){x=X,y=Y,l=L,r=R;}};
struct cmp{bool operator()(const edge &x,const edge &y)const{return x.l<y.l;}};
priority_queue<edge,vector<edge>,cmp>q;

struct node{int y,r,next;}a[4*maxn];int len,last[2][maxn];
void ins(int op,int x,int y,int r){a[++len].y=y;a[len].r=r;a[len].next=last[op][x];last[op][x]=len;}
int f[2][maxn];
int main()
{
	int n,m,x,y,l,r; edge p;
	scanf("%d%d",&n,&m);
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&l,&r); r--;
		if(l==r)q.push(edge(x,y,l,r)),q.push(edge(y,x,l,r));
		else
		{
			p=edge(x,y,l,r-(r-l)%2); q.push(p);
			p=edge(y,x,l,r-(r-l)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
		}
	}

	memset(f,-63,sizeof(f));f[0][1]=0;
	while(!q.empty())
	{
		p=q.top(); q.pop();
		int x=p.x,y=p.y,op=p.l&1;
		if(f[op][x]>=p.l)
		{
			if(y==n)
				{printf("%d\n",p.l+1);return 0;}

			f[op^1][y]=max(f[op^1][y],p.r+1);
			for(int k=last[op^1][y];k;k=a[k].next)
				if(p.l+1<=a[k].r)q.push(edge(y,a[k].y,p.l+1,a[k].r));
			last[op^1][y]=0;
		}
		else ins(op,x,y,r);
	}
	puts("-1");

	return 0;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int _=1e2;
const int maxn=5e5+_;
inline int read()
{
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}

struct edge{int x,y,l,r;edge(){}edge(int X,int Y,int L,int R){x=X,y=Y,l=L,r=R;}};
struct cmp{bool operator()(const edge &x,const edge &y){return x.l>y.l;}};
priority_queue<edge,vector<edge>,cmp>q;

struct node{int y,r,next;}a[4*maxn];int len,last[2][maxn];
void ins(int op,int x,int y,int r){a[++len].y=y;a[len].r=r;a[len].next=last[op][x];last[op][x]=len;}
int f[2][maxn];
int main()
{
	int n,m,x,y,l,r; edge p;
	n=read(),m=read();
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;i++)
	{
		x=read(),y=read(),l=read(),r=read()-1;
		if(l==r)q.push(edge(x,y,l,r)),q.push(edge(y,x,l,r));
		else
		{
			p=edge(x,y,l,r-(r-l)%2); q.push(p);
			p=edge(y,x,l,r-(r-l)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
			p=edge(y,x,l+1,r-(r-l-1)%2); q.push(p);
		}
	}

	memset(f,-63,sizeof(f));f[0][1]=0;
	while(!q.empty())
	{
		p=q.top(); q.pop();
		int x=p.x,y=p.y,op=p.l&1;
		if(f[op][x]>=p.l)
		{
			if(y==n)
				{printf("%d\n",p.l+1);return 0;}

			f[op^1][y]=max(f[op^1][y],p.r+1);
			for(int k=last[op^1][y];k;k=a[k].next)
				if(p.l+1<=a[k].r)q.push(edge(y,a[k].y,p.l+1,a[k].r));
			last[op^1][y]=0;
		}
		else ins(op,x,y,p.r);
	}
	puts("-1");

	return 0;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int _=1e2;
const int maxn=5e5+_;
inline int read()
{
	int x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x;
}

struct edge{int x,y,l,r;edge(){}edge(int X,int Y,int L,int R){x=X,y=Y,l=L,r=R;}};
struct cmp{bool operator()(edge x,edge y){return x.l>y.l;}};
priority_queue<edge,vector<edge>,cmp>q;

struct node{int y,r,next;}a[4*maxn];int len,last[2][maxn];
void ins(int op,int x,int y,int r){a[++len].y=y;a[len].r=r;a[len].next=last[op][x];last[op][x]=len;}
int f[2][maxn];
int main()
{
	int n,m,x,y,l,r; edge p;
	n=read(),m=read();
	if(n==1){puts("0");return 0;}
	for(int i=1;i<=m;i++)
	{
		x=read(),y=read(),l=read(),r=read()-1;
		if(l==r)q.push(edge(x,y,l,r)),q.push(edge(y,x,l,r));
		else
		{
			p=edge(x,y,l,r-(r-l)%2); q.push(p);
			p=edge(y,x,l,r-(r-l)%2); q.push(p);
			p=edge(x,y,l+1,r-(r-l-1)%2); q.push(p);
			p=edge(y,x,l+1,r-(r-l-1)%2); q.push(p);
		}
	}

	memset(f,-63,sizeof(f));f[0][1]=0;
	while(!q.empty())
	{
		p=q.top(); q.pop();
		int x=p.x,y=p.y,op=p.l&1;
		if(f[op][x]>=p.l)
		{
			if(y==n)
				{printf("%d\n",p.l+1);return 0;}

			f[op^1][y]=max(f[op^1][y],p.r+1);
			for(int k=last[op^1][y];k;k=a[k].next)
				if(p.l+1<=a[k].r)q.push(edge(y,a[k].y,p.l+1,a[k].r));
			last[op^1][y]=0;
		}
		else ins(op,x,y,p.r);
	}
	puts("-1");

	return 0;
}