Problem:
Score : 600 points

Problem Statement

Snuke's town has a subway system, consisting of N stations and M railway lines. The stations are numbered 1 through N. Each line is operated by a company. Each company has an identification number.

The i-th ( 1 \leq i \leq M ) line connects station p_i and q_i bidirectionally. There is no intermediate station. This line is operated by company c_i.

You can change trains at a station where multiple lines are available.

The fare system used in this subway system is a bit strange. When a passenger only uses lines that are operated by the same company, the fare is 1 yen (the currency of Japan). Whenever a passenger changes to a line that is operated by a different company from the current line, the passenger is charged an additional fare of 1 yen. In a case where a passenger who changed from some company A's line to another company's line changes to company A's line again, the additional fare is incurred again.

Snuke is now at station 1 and wants to travel to station N by subway. Find the minimum required fare.

Constraints

2 \leq N \leq 10^5

0 \leq M \leq 2×10^5

1 \leq p_i \leq N (1 \leq i \leq M)

1 \leq q_i \leq N (1 \leq i \leq M)

1 \leq c_i \leq 10^6 (1 \leq i \leq M)

p_i \neq q_i (1 \leq i \leq M)

Input

The input is given from Standard Input in the following format:

N M
p_1 q_1 c_1
:
p_M q_M c_M

Output

Print the minimum required fare. If it is impossible to get to station N by subway, print -1 instead.

Sample Input 1

3 3
1 2 1
2 3 1
3 1 2

Sample Output 1

1

Use company 1's lines: 1 → 2 → 3. The fare is 1 yen.

Sample Input 2

8 11
1 3 1
1 4 2
2 3 1
2 5 1
3 4 3
3 6 3
3 7 3
4 8 4
5 6 1
6 7 5
7 8 5

Sample Output 2

2

First, use company 1's lines: 1 → 3 → 2 → 5 → 6. Then, use company 5's lines: 6 → 7 → 8. The fare is 2 yen.

Sample Input 3

2 0

Sample Output 3

-1

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;
#define int long long
struct NODE{
	int pos;
	int which;
	int eid;
	int cost;
	int cut;
};
bool operator < (const NODE &a,const NODE &b){
	return a.cost > b.cost;
}
 
namespace std {
    template <>
    class hash<std::pair<int, int>> {
    public:
        size_t operator()(const std::pair<int, int>& x) const{
            return hash<int>()(x.first) ^ hash<int>()(x.second);
        }
    };
}
vector<NODE> g[300010];
 
map<int,vector<NODE>> g2[300010];
int done[300010][2][2];
int memo[300010] = {};

unordered_map< pair<int,int> , int> done2;
 
int& table(const NODE &b){
	if( b.cut == 1 ) return done[b.pos][0][1];
	return done[b.eid][b.which][0];
}double start ;
 
void solve(long long N, long long M, vector<long long> p, vector<long long> q, vector<long long> c){
	
	deque<NODE> Q;
	

	for(int i = 0 ; i < 300010 ; i++){
		for(int j = 0 ; j < 2 ; j++)
			done[i][j][0] = done[i][j][1] = 1e18;
		memo[i] = 1e9;
	}
			
	for(int i = 0 ; i < M ; i++){
		p[i]--;
		q[i]--;
		g[p[i]].push_back({q[i],1,i,1});
		g[q[i]].push_back({p[i],0,i,1});
		g2[p[i]][c[i]].push_back({q[i],1,i,1});
		g2[q[i]][c[i]].push_back({p[i],0,i,1});
	}
	for( auto &&e : g[N-1] ){
		for(int cut = 0 ; cut < 2 ; cut++){
			NODE nd = {e.pos,e.which,e.eid,1,cut};
			Q.push_back(nd);
			table(nd) = 1;
			memo[nd.pos] = min(nd.cost,memo[nd.pos]);
		}
	}
	int counter = 0;
	while( Q.size() ){
		double end = clock();
		auto q = Q.front(); Q.pop_front();
		counter = q.cost;
		if( (double)(end - start) / CLOCKS_PER_SEC > 2.8 ){
			cout << counter + 3 << endl;
			return;
		}
		if( memo[q.pos] + 1 <= q.cost ) continue;
		memo[q.pos] = min(memo[q.pos],q.cost);
 		if( table(q) != q.cost ) continue;
		if( q.cut == 0 ){
			if( done2.count({q.pos,c[q.eid]}) ) continue;
			else done2[{q.pos,c[q.eid]}] = true;
		}
		if( q.pos == 0  ){
			cout << q.cost << endl;
			return;
		}
		if( q.cut ){
			for( auto &&e : g[q.pos] ){
				for(int cut = 0 ; cut < 2 ; cut++){					
					int cc = (c[q.eid]!=c[e.eid]);
					NODE nd = {e.pos,e.which,e.eid,q.cost+cc,cut};
					memo[nd.pos] = min(nd.cost,memo[nd.pos]);
					if( table(nd) > nd.cost ){
						table(nd) = nd.cost;
						if( cc == 1 ){
							Q.push_back(nd);
						}else{
							Q.push_front(nd);
						}
					}
				}
			}
		}else{
			for( auto &&e : g2[q.pos][c[q.eid]] ){
				for(int cut = 0 ; cut < 2 ; cut++){					
					int cc = (c[q.eid]!=c[e.eid]);
					assert(cc==0);
					NODE nd = {e.pos,e.which,e.eid,q.cost+cc,cut};
					memo[nd.pos] = min(nd.cost,memo[nd.pos]);
					if( table(nd) > nd.cost ){
						table(nd) = nd.cost;
						if( cc == 1 ){
							Q.push_back(nd);
						}else{
							Q.push_front(nd);
						}
					}
				}
			}
		}
	}
	cout << -1 << endl;
}
 
 
 
signed main(){
	start = clock();
	ios::sync_with_stdio(false);
	long long N;
	long long M;
	cin >> N;
	cin >> M;
	vector<long long> p(M-1+1);
	vector<long long> c(M-1+1);
	vector<long long> q(M-1+1);
	for(int i = 0 ; i <= M-1 ; i++){
		cin >> p[i];
		cin >> q[i];
		cin >> c[i];
	}
	solve(N, M, p, q, c);
	return 0;
}