Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Problem H
Animal Companion in Maze

George, your pet monkey, has escaped, slipping the leash!

George is hopping around in a maze-like building with many rooms. The doors of the rooms, if any, lead directly to an adjacent room, not through corridors. Some of the doors, however, are one-way: they can be opened only from one of their two sides.

He repeats randomly picking a door he can open and moving to the room through it. You are chasing him but he is so quick that you cannot catch him easily. He never returns immediately to the room he just has come from through the same door, believing that you are behind him. If any other doors lead to the room he has just left, however, he may pick that door and go back.

If he cannot open any doors except one through which he came from, voila, you can catch him there eventually.

You know how rooms of the building are connected with doors, but you don't know in which room George currently is.

It takes one unit of time for George to move to an adjacent room through a door.

Write a program that computes how long it may take before George will be confined in a room. You have to find the longest time, considering all the possibilities of the room George is in initially, and all the possibilities of his choices of doors to go through.

Note that, depending on the room organization, George may have possibilities to continue hopping around forever without being caught.

Doors may be on the ceilings or the floors of rooms; the connection of the rooms may not be drawn as a planar graph.

Input

The input consists of a single test case, in the following format.

$n$ $m$

$x_1$ $y_1$ $w_1$

.

.

.

$x_m$ $y_m$ $w_m$

The first line contains two integers $n$ ($2 \leq n \leq 100000$) and $m$ ($1 \leq m \leq 100000$), the number of rooms and doors, respectively. Next $m$ lines contain the information of doors. The $i$-th line of these contains three integers $x_i$, $y_i$ and $w_i$ ($1 \leq x_i \leq n, 1 \leq y_i \leq n, x_i \ne y_i, w_i = 1$ or $2$), meaning that the $i$-th door connects two rooms numbered $x_i$ and $y_i$, and it is one-way from $x_i$ to $y_i$ if $w_i = 1$, two-way if $w_i = 2$.

Output

Output the maximum number of time units after which George will be confined in a room. If George has possibilities to continue hopping around forever, output "Infinite".

Sample Input 1

2 1
1 2 2

Sample Output 1

1

Sample Input 2

2 2
1 2 1
2 1 1

Sample Output 2

Infinite

Sample Input 3

6 7
1 3 2
3 2 1
3 5 1
3 6 2
4 3 1
4 6 1
5 2 1

Sample Output 3

4

Sample Input 4

3 2
1 3 1
1 3 1

Sample Output 4

1

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using Debug = System.Diagnostics.Debug;
//using System.Numerics;
//using static System.Math;
using Number = System.Int64;

namespace Program {
    public class Solver {
        //const long MOD = (long)1e9 + 7;
        public void Solve() {
            var n = ri;
            var m = ri;
            var f = new int[m];
            var t = new int[m];
            var w = new int[m];
            var s = new DisjointSet(n);
            var g = new SCCGraph(n);
            var G = Enumerate(n, x => new List<int>());
            var ok = true;
            for (int i = 0; i < m; i++) {
                f[i] = ri - 1; t[i] = ri - 1; w[i] = ri;
                G[f[i]].Add(t[i]);
                if (w[i] == 2) {
                    ok &= s.Unite(f[i], t[i]);
                    G[t[i]].Add(f[i]);
                }
            }
            for (int i = 0; i < m; i++)
                if (w[i] == 1) g.AddEdge(s[f[i]], s[t[i]]);
            g.Build();
            for (int i = 0; i < g.Count; i++)
                ok &= g.scc[i].Count == 1;
            if (!ok) { Console.WriteLine("Infinite"); return; }

            var dp = Enumerate(n, x => -1);
            Func<int, int, int> dfs = null;
            Action<int, int, int> efs = null;

            dfs = (prev, cur) => {
                if (dp[cur] != -1) return dp[cur];
                var ret = 0;
                var root = prev == -1 || !s.IsUnited(prev, cur);
                foreach (var to in G[cur]) {
                    if (prev == to) continue;
                    ret = Math.Max(ret, 1 + dfs(cur, to));
                }
                if (root) efs(-1, cur, -1000000);
                return dp[cur] = ret;
            };
            efs = (prev, cur, max) => {
                //Debug.WriteLine($"efs {prev} {cur} {max}");
                var d = G[cur].Count;
                var dpv = new int[d + 1];
                var dpR = new int[d + 1];
                for (int i = 0; i < d; i++)
                    if (G[cur][i] != prev) dpv[i] = 1 + dp[G[cur][i]];
                    else dpv[i] = 1 + max;
                for (int i = d - 1; i >= 0; i--)
                    dpR[i] = Math.Max(dpR[i + 1], dpv[i]);
                var vl = 0;
                for (int i = 0; i < d; i++) {
                    if (G[cur][i] != prev && s.IsUnited(cur, G[cur][i])) {
                        efs(cur, G[cur][i], Math.Max(vl, dpR[i + 1]));
                    }
                    vl = Math.Max(vl, dpv[i]);
                }
                dp[cur] = vl;
            };
            var ans = 0;
            for (int i = 0; i < n; i++) ans = Math.Max(ans, dfs(-1, i));
            Debug.WriteLine(dp.AsJoinedString());
            Console.WriteLine(ans);
        }

        const long INF = 1L << 60;
        //int[] dx = { 1, 0, -1, 0 };
        //int[] dy = { 0, 1, 0, -1 };
        //*
        int ri { get { return sc.Integer(); } }
        long rl { get { return sc.Long(); } }
        double rd { get { return sc.Double(); } }
        string rs { get { return sc.Scan(); } }
        //*/

        public IO.StreamScanner sc = new IO.StreamScanner(Console.OpenStandardInput());
        static T[] Enumerate<T>(int n, Func<int, T> f) { var a = new T[n]; for (int i = 0; i < n; ++i) a[i] = f(i); return a; }
        static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
    }
}

#region main
static class Ex {
    static public string AsString(this IEnumerable<char> ie) { return new string(ie.ToArray()); }
    static public string AsJoinedString<T>(this IEnumerable<T> ie, string st = " ") {
        return string.Join(st, ie.Select(x => x.ToString()).ToArray());
        //return string.Join(st, ie);
    }
    static public void Main() {
        Console.SetOut(new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        var solver = new Program.Solver();
        solver.Solve();
        Console.Out.Flush();
    }
}
#endregion
#region Ex
namespace Program.IO {
    using System.Globalization;
    using System.IO;
    using System.Text;
    public class Printer: StreamWriter {
        public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
        public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
    }
    public class StreamScanner {
        public StreamScanner(Stream stream) { str = stream; }
        public readonly Stream str;
        private readonly byte[] buf = new byte[1024];
        private int len, ptr;
        public bool isEof = false;
        public bool IsEndOfStream { get { return isEof; } }
        private byte read() {
            if (isEof) return 0;
            if (ptr >= len) { ptr = 0; if ((len = str.Read(buf, 0, 1024)) <= 0) { isEof = true; return 0; } }
            return buf[ptr++];
        }
        public char Char() { byte b = 0; do b = read(); while ((b < 33 || 126 < b) && !isEof); return (char)b; }

        public string Scan() {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read())
                sb.Append(b);
            return sb.ToString();
        }
        public string ScanLine() {
            var sb = new StringBuilder();
            for (var b = Char(); b != '\n' && b != 0; b = (char)read())
                if (b != '\r') sb.Append(b);
            return sb.ToString();
        }
        public long Long() { return isEof ? long.MinValue : long.Parse(Scan()); }
        public int Integer() { return isEof ? int.MinValue : int.Parse(Scan()); }
        public double Double() { return isEof ? double.NaN : double.Parse(Scan(), CultureInfo.InvariantCulture); }
    }
}
#endregion

#region DisjointSet
public class DisjointSet {
    int[] par;
    byte[] rank;
    public DisjointSet(int n) {
        par = new int[n];
        for (int i = 0; i < n; i++)
            par[i] = -1;
        rank = new byte[n];
    }
    public int this[int id] {
        get {
            if ((par[id] < 0)) return id;
            return par[id] = this[par[id]];
        }
    }
    public bool Unite(int x, int y) {
        x = this[x]; y = this[y];
        if (x == y) return false;
        if (rank[x] < rank[y]) { var z = x; x = y; y = z; }
        par[x] += par[y];
        par[y] = x;
        if (rank[x] == rank[y])
            rank[x]++;
        return true;
    }
    public int Size(int x) { return -par[this[x]]; }
    public bool IsUnited(int x, int y) { return this[x] == this[y]; }

}
#endregion

#region SCCGraph
public class SCCGraph {
    int n;

    List<int>[] g;
    public List<List<int>> scc;
    int[] group;

    /// <summary>
    /// ?????£?????????????????????
    /// </summary>
    public int Count { get; private set; }

    public SCCGraph(int N) {
        n = N;
        g = new List<int>[n];
        scc = new List<List<int>>();
        for (int i = 0; i < n; i++)
            g[i] = new List<int>();
    }
    public void AddEdge(int f, int t) { g[f].Add(t); }
    public int this[int id] { get { return group[id]; } }
    public void Build() {
        Decomposite();
        scc.Reverse();
        group = new int[n];
        for (int i = 0; i < Count; i++)
            foreach (var x in scc[i]) group[x] = i;

    }
    /// <summary>
    /// ?????£?????????????§£?????????
    /// </summary>
    public int Decomposite() {
        var S = new Stack<int>(n + 2);
        var B = new Stack<int>(n + 2);
        var I = new int[n];
        var iter = new int[n];
        var s = new Stack<int>(n + 2);
        for (int i = 0; i < n; i++) {
            if (I[i] != 0) continue;
            s.Push(i);
            while (s.Count > 0) {
                DFS:
                var u = s.Peek();
                if (I[u] == 0) {
                    B.Push(I[u] = S.Count);
                    S.Push(u);
                    iter[u] = 0;
                }
                while (iter[u] < g[u].Count) {
                    var v = g[u][iter[u]++];
                    if (I[v] == 0) {
                        s.Push(v);
                        goto DFS;
                    }
                    else while (I[v] < B.Peek()) B.Pop();
                }
                if (I[u] == B.Peek()) {
                    var ns = new List<int>();
                    scc.Add(ns);
                    B.Pop();
                    while (I[u] < S.Count) {
                        var p = S.Pop();
                        ns.Add(p);
                        I[p] = n + scc.Count;
                    }
                }
                s.Pop();

            }
        }
        return Count = scc.Count;

    }
    public bool IsSameGroup(int u, int v) { return group[u] == group[v]; }
}
#endregion