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# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

public struct Z2 {
    public int x, y;
    public Z2(int x, int y){
        this.x = x;
        this.y = y;
    }
}

public class IPQ{
    private List<Z2> array;
    private int size;
    
    
    public IPQ(int capacity){
        this.array = new List<Z2>(capacity);
        this.size = 0;
    }
    public void Clear(){
        array.Clear();
        this.size = 0;
    }
    public bool Empty(){ return size==0; }
    public Z2 Front(){ return (size==0)? new Z2(0,0):array[0]; }
    public Z2 Pop(){
        if(size < 1) return new Z2(0,0);
        Z2 min = array[0];
        array[0] = array[size-1];
        size--;
        int i = 0;
        while(true){
            int l = 2*i+1, r = 2*i+2,smallest = i;
            if(l<size && array[l].x < array[i].x) smallest = l;
            if(r<size && array[r].x < array[smallest].x) smallest = r;
            if(smallest == i) break;
            Z2 tmp = array[i];
            array[i] = array[smallest];
            array[smallest] = tmp;
            i = smallest;
        }
        return min;
    }
    
    public void Push(Z2 key){
        size = size + 1;
        if( array.Count < size){
            array.Add(key);
        }  else {
            array[size-1] = key;
        }
        int i = size-1;
        while(i>0 && array[(i-1)/2].x>array[i].x){
            Z2 tmp = array[i];
            array[i] = array[(i-1)/2];
            array[(i-1)/2] = tmp;
            i = (i-1)/2;
        }
    }
}



public class FDijkstra {
    int[,] input;
    int[] index;
    int V,E;
    
    int[,] G;
    int[] d;
    const int INF = int.MaxValue;
    
    public FDijkstra(int V, int E){
        this.V = V; this.E = E;
        
        index = new int[V+1];
        G = new int[E,2];
       
       count = 0;
    }
    
    int count = 0;
    public void Input(int x, int y, int cost){
        if(count==0) input = new int[E, 3];
        if(count > E) throw new ArgumentOutOfRangeException();
        input[count, 0] = x; input[count, 1] = y; input[count, 2] = cost;
        index[x+1]++;
        count++;
        if(count == E){
            for(int i=0;i<V;i++){
                index[i+1] = index[i] + index[i+1];
            }
            if(index[V]!=E) throw new ArgumentException();
            
            int[] pos = new int[V];
            for(int i=0;i<V;i++) pos[i] = index[i];
            for(int i=0;i<E;i++){
                int a = input[i,0], b = input[i,1], cst = input[i,2];
                int psa = pos[a];
                G[psa,0] = b; G[psa,1] = cst;
                pos[a]++;
            }
        }
    }
    public void Input2( int[,] inp, byte[] im, int IE){
        if(IE !=  E) throw new ArgumentOutOfRangeException();
        count = IE;
        for(int i=0;i<IE;i++) index[inp[i,0]+1]++;
      
        for(int i=0;i<V;i++){
            index[i+1] = index[i] + index[i+1];
        }
        if(index[V]!=E) throw new ArgumentException();
        
        int[] pos = new int[V];
        for(int i=0;i<V;i++) pos[i] = index[i];
        for(int i=0;i<E;i++){
            int a = inp[i,0], b = inp[i,1], cst = im[i];
            int psa = pos[a];
            G[psa,0] = b; G[psa,1] = cst;
            pos[a]++;
        }
        
    }
    
    
    public void Dijkstra(int s){
        if(count != E) Console.WriteLine("Not Ready");
        IPQ hp = new IPQ(E);
        d = new int[V];
        for(int i=0;i<d.Length;i++) d[i] = INF;
        d[s] = 0;
        hp.Push(new Z2(0,s));
        while(!hp.Empty()){
            Z2 p = hp.Pop();
            int v = p.y;
            if(d[v]<p.x) continue;
            int start = index[v], end = index[v+1];
            for(int i=start; i<end; i++){
                int next = G[i,0], cost = G[i,1];
                if(d[next]>d[v]+cost){
                    d[next] = d[v]+cost;
                    hp.Push(new Z2(d[next],next));
                }
            }
        }
    }
    
    public int GetDistance(int t){
        if(d[t]==INF) throw new ArgumentException();
        return d[t];
    }
}

 
 
public class A {
	int N,M;
    
	
	public A(){
	}
	
	string[] Rs(){
		return Console.ReadLine().Split(' ');
	}
	public void run(){
        string[] str = Rs();
		N = int.Parse(str[0]); M = int.Parse(str[1]);
        Dictionary<Z2, int> hs = new Dictionary<Z2,int>(2*M+N+10);
        int cnt1 = 0;
        for(int i=0;i<N;i++){
            hs.Add(new Z2(i,-1), cnt1);
            cnt1++;
        }
        int cnt2 = 0;
        int[,] input = new int[6*M,2]; 
        byte[] inp = new byte[6*M];
        
        Action<int, int, byte> f = (x, y, c) => {
            input[cnt2,0] = x; input[cnt2,1] = y; inp[cnt2] = c;
            cnt2++;
        };
        
        for(int i=0;i<M;i++){
            int[] ip = Rs().Select( x => int.Parse(x)-1 ).ToArray();
            int i0 = ip[0];
            int i1 =ip[1];
            int i2 = ip[2];
            
            Z2 e0 = new Z2(i0, i2), e1 = new Z2(i1, i2);
            Z2 ne0 = new Z2(i0, -1), ne1 = new Z2(i1, -1);
            int hne0 = hs[ne0], hne1 = hs[ne1];
            
            if(!hs.ContainsKey(e0)){
                hs.Add(e0, cnt1);
                cnt1++;
                f(hs[e0],hne0,0);f(hne0, hs[e0], 1);
            }
            if(!hs.ContainsKey(e1)){
                hs.Add(e1, cnt1);
                cnt1++;
                f(hs[e1],hne1,0);f(hne1, hs[e1],1);
            }
            f(hs[e0], hs[e1], 0);
            f(hs[e1], hs[e0], 0);
            
        }
        int end = hs[new Z2(N-1, -1)];
        FDijkstra dij = new FDijkstra(cnt1,cnt2);
        dij.Input2(input,inp,cnt2);
        dij.Dijkstra(0);
        
        try {
            int ans = dij.GetDistance(end);
            Console.WriteLine(ans);
        } catch(Exception e){
            Console.WriteLine("-1");
        }
        
	}
}
 
public class Program {
	static void Main(string[] args){
		A a = new A();
        var th = new Thread(a.run,150*1024*2024);
        th.Start();
	}
}