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: Wrong Answer)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static long[] distanceMemos = new long[2];//キューから捨てた最短距離と頂点番号
static string[] input = Console.ReadLine().Split(' ');
static int n = int.Parse(input[0]);
static int e = int.Parse(input[1]);
static long[] vertexes = new long[2*e];

  static void Main()
  {
    long[,] edges = new long[6*e+2,3];
    long[] answers = new long[2*e+n+2];
    long[,] numss = new long[e,3];

    for(long i = 0; i < e; i++)
    {
      long[] nums = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);
      numss[i,0] = nums[0]-1;
      numss[i,1] = nums[1]-1;
      numss[i,2] = nums[2];
      vertexes[2*i] = (nums[0]-1)+nums[2]*1000000;
      vertexes[2*i+1] = (nums[1]-1)+nums[2]*1000000;
    }
    Array.Sort(vertexes);

    edges[0,0] = 0;
    edges[0,1] = 1;
    edges[0,2] = 0;
    edges[1,0] = n;
    edges[1,1] = 2*e+n+1;
    edges[1,2] = 0;
    
    for(int i = 0; i < e; i++)
    {
      edges[6*i+2,0] = numss[i,0]+1;
      edges[6*i+2,1] = n+1+Search(0,2*e-1,-1,(numss[i,0]-1)+numss[i,2]*1000000);
      edges[6*i+2,2] = 1;
      edges[6*i+3,0] = n+1+Search(0,2*e-1,-1,numss[i,0]+numss[i,2]*1000000);
      edges[6*i+3,1] = n+1+Search(0,2*e-1,-1,numss[i,1]+numss[i,2]*1000000);
      edges[6*i+3,2] = 0;
      edges[6*i+4,0] = n+1+Search(0,2*e-1,-1,(numss[i,1]-1)+numss[i,2]*1000000);
      edges[6*i+4,1] = numss[i,1]+1;
      edges[6*i+4,2] = 0;

      edges[6*i+5,0] = n+1+Search(0,2*e-1,-1,(numss[i,0]-1)+numss[i,2]*1000000);
      edges[6*i+5,1] = numss[i,0]+1;
      edges[6*i+5,2] = 0;
      edges[6*i+6,0] = n+1+Search(0,2*e-1,-1,numss[i,1]+numss[i,2]*1000000);
      edges[6*i+6,1] = n+1+Search(0,2*e-1,-1,numss[i,0]+numss[i,2]*1000000);
      edges[6*i+6,2] = 0;
      edges[6*i+7,0] = numss[i,1]+1;
      edges[6*i+7,1] = n+1+Search(0,2*e-1,-1,(numss[i,1]-1)+numss[i,2]*1000000);
      edges[6*i+7,2] = 1;
    }
     
    answers = Dijkstra(2*e+n+2,6*e+2,1,edges);
    Console.WriteLine((answers[n] == -1? "-1" : answers[n].ToString()));
  }

  static long Search(long min, long max, int MinorMax, long a)//二分探索法で最小値-1最大値1を求める
  {
    while (true)
    {
      long mid = min + (max - min) / 2;
      if(MinorMax == 1)
      {
        if(Check(mid,a)) min = mid;//さらに大きくても成り立つかも
        else max = mid;
      }else
      {
        if(Check(mid,a)) max = mid;//さらに小さくても成り立つかも
        else min = mid;
      }

      if(max - min <= 1)
      {
        if(MinorMax == 1)
        {
          if(Check(max,a)) return max;//最大値で成り立つかの確認を優先
          else return min;
        }else
        {
          if(Check(min,a)) return min;//最小値で成り立つかの確認を優先
          else return max;
        }

      break;
      }  
    }
  }

  static bool Check(long testNum, long a)
  {
    if(vertexes[testNum] >= a) return true;
    return false;
  }  

 
  static long[] Dijkstra(int vertexCount, int edgeCount, int startV, long[,] edges)
  {//ダイクストラ法により、O((|頂点数|+|辺数|)log頂点数)で各頂点への最短距離を求める
  //引数は頂点数、辺数、開始頂点(0-index)、辺の始点と終点と距離
  //返り値は各頂点までの最短距離、ただし到達できない場合は-1

    int n = vertexCount;
    List<long[]>[] nextList = new List<long[]>[n];//頂点番号ごとの隣接リスト。距離、隣接頂点番号
    for(long i = 0; i < n; i++)
    {
      nextList[i] = new List<long[]>();//リストの宣言が必要
    }
    long[] colors = new long[n];//最短距離未確定の頂点が0、確定で2
    long[] distances = new long[n];//各頂点への最短距離

    for(long i = 0; i < edgeCount; i++)
    {
      long[] nextMemo = new long[2];
      nextMemo[1] = edges[i,1];//隣接頂点番号
      nextMemo[0] = edges[i,2];//距離
      nextList[edges[i,0]].Add(nextMemo);//隣接リストの作成
    }
  
    List<long[]> distanceList = new List<long[]>();//優先度付きキュー
    for(long i = 0; i < n; i++)
    {
      distances[i] = long.MaxValue;//最短距離を無限とおく
    }
 
    long[] newDistance = new long[2];
 
    //スタート地点を決める
    newDistance[1] = startV;//スタート地点番号
    distances[startV] = 0;
    colors[startV] = 1;
 
    newDistance[0] = 0;//スタートからスタートまでの距離0
    distanceList.Add(newDistance);
 
    while(distanceList.Count() != 0)
    {
      distanceList = PopHeap(distanceList);
      long minVertex = distanceMemos[1];//最短頂点の番号
      colors[minVertex] = 2;
      if(distances[minVertex] < distanceMemos[0]) continue;//最小値が最短でないなら無視
 
      for(long i = 0; i < nextList[minVertex].Count(); i++)
      {
        long v = nextList[minVertex][(int)i][1];
        if(colors[v] == 2) continue;
        if(distances[v] > distances[minVertex] + nextList[minVertex][(int)i][0])
        {
          distances[v] = distances[minVertex] + nextList[minVertex][(int)i][0];
          long[] newDistanceSub = new long[2];
          newDistanceSub[0] = distances[v];
          newDistanceSub[1] = v;
          distanceList = PushHeap(distanceList, newDistanceSub);
          colors[v] = 1;
        }
      }
    }

    for(long i = 0; i < n; i++)
    {
      if(distances[i] == long.MaxValue) distances[i] = -1;
        //全頂点について最短距離の出力。到達不可能な頂点は-1を出力。
    }
    return distances;
  }
 
  //引数は、昇順にソート済みのリスト
  static List<long[]> PushHeap(List<long[]> nums, long[] addNums)//現在のヒープnumsにaddNumを追加
  {
    int n = nums.Count;
    nums.Add(addNums);
 
    while (n > 0)
    {
      int i = (n-1)/2;
      if (nums[n][0] < nums[i][0])//親のほうが大きいなら入れ替え。
      {
        long tmp = nums[n][0];
        long tmpSub = nums[n][1];
        nums[n][0] = nums[i][0];
        nums[n][1] = nums[i][1];
        nums[i][0] = tmp;
        nums[i][1] = tmpSub;
      }
      n = i;
    }
    return nums;
  }
 
  static List<long[]> PopHeap(List<long[]> nums)//ヒープnumsからポップ
  {
    int n = nums.Count - 1;
    distanceMemos[0] = nums[0][0];//捨てる値の保存
    distanceMemos[1] = nums[0][1];
    nums[0][0] = nums[n][0];//最小値である根を削除してリストの最後を持ってくる
    nums[0][1] = nums[n][1];
    nums.RemoveAt(n);
 
    for (int i = 0, j; (j = 2*i+1) < n; )
    {
      if ((j != n-1) && (nums[j][0] > nums[j+1][0]))// ２つの子のうち、値の小さい方を選ぶ
        j++;
      if (nums[i][0] > nums[j][0])//子が親より小さいなら入れ替え
      {
        long tmp = nums[j][0];
        long tmpSub = nums[j][1];
        nums[j][0] = nums[i][0];
        nums[j][1] = nums[i][1];
        nums[i][0] = tmp;
        nums[i][1] = tmpSub;
      }
      i = j;
    }
    return nums;
  }
   
}