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: Accepted)

//#include "debug.h"
#include <string.h>
#include <limits.h>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

//#include "set/union_find_g.h"
template<class T>
struct gufs {
	map<T,T> f;
	map<T,int> c;
	T find(T v) {
		T r, u;
		for(r=v; f.find(r) != f.end(); r=f[r]);
		for(u=v; u!=r; ) {
			T t = f[u];
			f[u] = r;
			u = t;
		}
		if (c.find(r)==c.end()) c[r] = 1;
		return r;
	}
	T merge(T a, T b) {
		a = find(a);
		b = find(b);
		if (a!=b) {
			f[a] = b;
			c[b] += c[a];
		}
		return b;
	}
	void clear() {
		f.clear();
		c.clear();
	}
	int count(int v){
		return c[find(v)];
	}
	void get_sets(map<T,vector<T>> &s) {
		for (auto &x: f) {
			s[find(x.first)].push_back(x.first);
		}
		for (auto &x: s) {
			s[x.first].push_back(x.first);
		}
	}
};

#define MAXN 100000

int n, m;
vector<pair<int,int>> g[MAXN];

map<int, gufs<int>> uf;
map<int, map<int, vector<int>>> us;

int q[MAXN];
int h, t;
int dist[MAXN];

void adde(int a, int b, int c) {
	g[a].push_back({b,c});
	g[b].push_back({a,c});
	uf[c].merge(a, b);
}

int input() {
	if (scanf("%d %d", &n, &m) < 0) return 0;
	for (int i=0; i<m; i++) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		a--, b--, c--;
		adde(a,b,c);
	}
	return 1;
}

void init() {
	for (int i=0; i<n; i++) dist[i] = INT_MAX;
	for (auto &x: uf)
		x.second.get_sets(us[x.first]);
}

int solve() {
	h=0, t=0;
	dist[0] = 0;
	q[t++] = 0;
	set<pair<int,int>> done;
	while (h<t) {
		int v = q[h++], d = dist[v]+1;
		//printf("-->v=%d d=%d\n", v, d);
		for(auto &x: g[v]) {
			int u = x.first, c = x.second;

			//need to process when dist[u]==d
			if (dist[u] < d) continue;

			int r = uf[c].find(v);

			//!! speed up
			if (done.count({c,r})) continue;
			done.insert({c,r});

			for (auto &x: us[c][r]) {
				if (d < dist[x]) {
					dist[x] = d;
					q[t++] = x;
				}
			}
		}
	}
	//cout << us << endl; printa(dist,n);
	return dist[n-1];
}

void output(int ans) {
	printf("%d\n", ans==INT_MAX? -1: ans);
}

void cleanup() {
	for (int i=0; i<n; i++) g[i].clear();
	uf.clear();
	us.clear();
}

int main() {
	//int ca; scanf("%d", &ca);
	while (input()) {
		init();
		output(solve());
		cleanup();
		//break;
	}
}