Problem:
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

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5 + 50;

int n , m , fa[maxn] , dfn[maxn] , low[maxn] , vis[maxn] , dfs_clock , scc_idx[maxn] , scc_tot , has_circle , Dp[maxn] , f[maxn] , g[maxn];
stack < int > stk;
vector < int > SavDs[maxn];

int find_fa( int u ){
	return fa[u] != u ? fa[u] = find_fa( fa[u] ) : u;
}

vector < int > Edge[maxn] , G[maxn] , TG[maxn] , Normal[maxn];

void Dfs_Circle( int u ){
	dfn[u] = low[u] = ++ dfs_clock;
	stk.push( u );
	for(auto v : TG[u]){
		if(!dfn[v]){
			Dfs_Circle( v );
			low[u] = min( low[u] , low[v] );
		}else if( !scc_idx[v] )
			low[u] = min( low[u] , dfn[v] );
	}
	if( low[u] == dfn[u] ){
		++scc_tot;
		int cnt = 0;
		while( 1 ){
			int x = stk.top();stk.pop();
			++ cnt;
			scc_idx[x] = scc_tot;
			if( x == u )
				break;
		}
		has_circle |= ( cnt > 1 );
	}
}

function < vector < int > ( int ) > Bfs = [ & ]( const int & base ){
	queue < int > que;
	vector < int > Final;
	que.push( base );
	vis[base] = 1;
	while( !que.empty() ){
		int x = que.front() ; que.pop();
		Final.emplace_back( x );
		for(auto v : Normal[x])
			if( !vis[v] ){
				vis[v] = 1;
				que.push( v );
			}
	}
	return Final;
};

void InsertValue( vector < int > & x , int y ){
	if( x.size() < 2 ){
		x.emplace_back( y );
		if( x.size() == 2 && x[0] < x[1] )
			swap( x[0] , x[1] );
	}else{
		if( y > x[0] )
			x[1] = x[0] , x[0] = y;
		else if( y > x[1] )
			x[1] = y;
	}
}

int Dfs( int u ){
	if( ~Dp[u] )
		return Dp[u];
	int & ans = Dp[u] = 0;
	vector < int > basement = Bfs( u );
	/*for(auto it : basement)
		cout << it << " ";
	cout << endl;*/
	function < void( int , int ) > PreDfs = [ & ]( int u , int fa ){
		f[u] = 0;
		for(auto v : Normal[u]){
			if( v == fa )
				continue;
			PreDfs( v , u );
			f[u] = max( f[u] , f[v] + 1 );
			InsertValue( SavDs[u] , f[v] + 1 );
		}
		for(auto v : G[u]){
			f[u] = max( f[u] , Dfs( v ) + 1 );
			InsertValue( SavDs[u] , Dfs( v ) + 1 );
		}
		for(auto v : Normal[u]){
			if( v == fa )
				continue;
			if( SavDs[u][0] == f[v] + 1 )
				g[v] = SavDs[u].size() == 2 ? SavDs[u][1] : -(1 << 30);
			else
				g[v] = SavDs[u][0];
 		}
	};
	function < void( int , int , int ) > SecondDfs = [ & ]( int u , int fa , int preDp ){
		Dp[u] = max( f[u] , preDp );
		for(auto v : Normal[u]){
			if( v == fa )
				continue;
			SecondDfs( v , u , max( preDp , g[v] ) + 1 );
		}
	};
	PreDfs( u , 0 );
	SecondDfs( u , 0 , -(1 << 30) );
	return ans;
}

int main( int argc , char * argv[] ){
	scanf( "%d%d" , & n , & m );
	for(int i = 1 ; i <= n ; ++ i)
		fa[i] = i;
	for(int i = 1 ; i <= m ; ++ i){
		int u , v , type;
		scanf( "%d%d%d" , & u , & v , & type );
		Edge[u].emplace_back( v );
		if( type == 2 ){
			Edge[v].emplace_back( u );
			Normal[u].emplace_back( v );
			Normal[v].emplace_back( u );
			int p1 = find_fa( u ) , p2 = find_fa( v );
			if( p1 == p2 ){
				puts( "Infinite" );
				return 0;
			}
			fa[p1] = p2;
		}else
			G[u].emplace_back( v );
	}
	for(int i = 1 ; i <= n ; ++ i)
		for(auto j : G[i])
			if( find_fa( i ) == find_fa( j ) ){
				puts( "Infinite" );
				return 0;
			}else
				TG[find_fa( i )].emplace_back( find_fa( j ) );
	for(int i = 1 ; i <= n ; ++ i)
		if( !dfn[i] )
			Dfs_Circle( i );
	if( has_circle ){
		puts( "Infinite" );
		return 0;
	}
	memset( Dp , -1 , sizeof( Dp ) );
	int ans = 0;
	for(int i = 1 ; i <= n ; ++ i)
		ans = max( ans , Dfs( i ) );
	printf( "%d\n" , ans );
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 37584
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n, m, g, ans;
bool inf = false;
struct Edge {
    int from, to, id;
};
Edge edges[maxn];
vector<Edge> uni[maxn];
vector<Edge> bid[maxn];
vector<int> member[maxn];
int in[maxn], root[maxn];
int x[maxn], y[maxn], w[maxn], grp[maxn], dp[maxn];
queue<int> q;
//计算浓缩点内部
struct Item {
    int v, from;
};
Item items[maxn][2];
int fa[maxn];
bool gen_grp (int rt, int f) {
    //printf ("goto :%d %d\n", rt, bid[rt].size());
    grp[rt] = g;
    member[g].push_back (rt);
    for (int i = 0; i < bid[rt].size(); i++) if (bid[rt][i].id != f) {
        Edge e = bid[rt][i];
        //printf ("%d %d %d\n", e.from, e.to, e.id);
        fa[e.to] = rt;
        if (grp[e.to] != 0) return false;
        if (!gen_grp(e.to, e.id)) return false;
    }
    return true;
}
void get (int u, int fr) {
    Item item;
    if (items[fr][0].from != u) item = items[fr][0];
    else item = items[fr][1];
    item.v++;
    item.from = fr;
//    printf ("%d get (%d, %d)\n", u, item.v, item.from);
    if (item.v > items[u][0].v) {
        items[u][1] = items[u][0];
        items[u][0] = item;
    }
    else if (item.v > items[u][1].v) {
        items[u][1] = item;
    }
}
bool gen_item1 (int rt, int f) {
    items[rt][0] = (Item){dp[rt], rt};
    items[rt][1] = (Item){0, rt};
    for (int i = 0; i < bid[rt].size(); i++) if (bid[rt][i].id != f) {
        gen_item1 (bid[rt][i].to, bid[rt][i].id);
        get (rt, bid[rt][i].to);
    }
}
bool gen_item2 (int rt, int f) {
    if (fa[rt] != 0) get (rt, fa[rt]);
    for (int i = 0; i < bid[rt].size(); i++) if (bid[rt][i].id != f) {
        gen_item2 (bid[rt][i].to, bid[rt][i].id);
    }
}
//
void update (int u) {
    for (int i = 0; i < uni[u].size(); i++) {
        Edge e = uni[u][i];
        dp[e.to] = max (items[u][0].v+1, dp[e.to]);
        in[grp[e.to]]--;
        if (in[grp[e.to]] == 0)  q.push (grp[e.to]);
    }
}

void UPDATE (int u) {
    gen_item1 (root[u], 0);
    gen_item2 (root[u], 0);
    for (int i = 0; i < member[u].size(); i++) {
        update (member[u][i]);
    }
}
int solve () {
    int ans = 0;
    for (int i = 1; i <= m; i++) if (w[i] == 2) {
        bid[x[i]].push_back ({x[i], y[i], i});
        bid[y[i]].push_back ({y[i], x[i], i});
    }
    for (int i = 1; i <= n; i++) if (!grp[i]) {
        ++g;
        root[g] = i;
        if (!gen_grp (i, 0)) return -1;
    }
    for (int i=  1; i <= m; i++) if (w[i] == 1) {
        if (grp[x[i]] == grp[y[i]]) return -2;
        uni[x[i]].push_back ({x[i], y[i], i});
        in[grp[y[i]]]++;
    }
    for (int i = 1; i <= g; i++) if (!in[i]) {
        q.push (i);
    }
    while (!q.empty()) {
        int u = q.front(); q.pop();
        UPDATE (u);
    }
    for (int i = 1; i <= g; i++) if (in[i] != 0) {
        return -3;
    }
    for (int i = 1; i <= n; i++) {
        ans = max (items[i][0].v, ans);
//        printf ("%d: %d\n", i, items[i][0].v);
    }
    return ans;
}
int main () {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= m; i++){
        scanf ("%d%d%d", &x[i], &y[i], &w[i]);
    }
    ans = solve ();
    if (ans <= -1) printf ("Infinite\n");
    else printf ("%d\n", ans);
//    for (int i = 1; i <= n; i++) {
//        printf ("%d belong to group %d\n", i, grp[i]);
//    }
}
accuracy: 0.08108108108108109
time_ms: 20
memory_kb: 21960
final_rank: 12

code_snippet: #include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 1000001
int dfn[MAXN], low[MAXN], stack[MAXN];
int res[MAXN];
bool flag[MAXN];
vector<int> e[MAXN];
int cur, top, cnt;//cur为访问标号，top为栈顶，cnt为强连通分量个数
//使用前清空dfn,flag数组，cur，cnt置0；返回res存储每个点所在强连通分量集合
void tarjan(int i)
{
    low[i] = dfn[i] = ++cur;
    stack[++top] = i; flag[i] = true;
    for (unsigned j = 0; j < e[i].size(); j++){
        int id = e[i][j];
        if (!dfn[id]){
            tarjan(id);
            low[i] = min(low[i], low[id]);
        }
        else if (flag[id])
            low[i] = min(low[i], dfn[id]);//此处可写low
    }
    if (low[i] == dfn[i]){
        cnt++;
        int t;
        do{
            t = stack[top--];
            res[t] = cnt;
            flag[t] = false;
        } while (t != i);
    }
}

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<int> v[1000001];
int degree[1000001];
int ans[1000001], layer[1000001];//ans为拓扑序列，layer为每个结点层数
//返回值为true表示成功，false表示有环
bool toposort(int n)
{
    int k = 0;
    memset(degree + 1, 0, sizeof(int)*n);
    memset(layer + 1, 0, sizeof(int)*n);
    for (int i = 1; i <= n; i++){
        for (unsigned int t = 0; t < v[i].size(); t++)
            degree[v[i][t]]++;
    }
    for (int i = 1; i <= n; i++){
        if (!degree[i])ans[k++] = i;
    }
    for (int j = 0; j < k; j++){
        for (unsigned int t = 0; t < v[ans[j]].size(); t++){
            int i = v[ans[j]][t];
            if (!--degree[i]){
                ans[k++] = i;
                layer[i] = layer[ans[j]] + 1;
            }
        }
    }
    return k == n;
}

vector<int> vv[200001];
vector<int> s[200001];
int f[200001];
bool vis[200001];
int getFather(int i){
    if(!f[i])return i;
    return f[i]=getFather(f[i]);
}
struct Edge{
    int x,y,w;
}ee[200001];
int out[200001];
int dp[200001],dp2[200001],dp3[200001],son[200001];
void dfs1(int i,int fa)
{
    dp2[i]=dp[i];
    for(int j:vv[i]){
        if(j!=fa){
            dfs1(j,i);
            int t=dp[j]+1;
            if(t>dp[i]){dp2[i]=dp[i];dp[i]=t;son[i]=j;}
            else if(t>dp2[i]){dp2[i]=t;}
        }
    }
}
void dfs2(int i,int fa)
{
    for(int j:vv[i]){
        if(j!=fa){
            if(j==son[i])dp3[j]=dp2[i]+1;
            else dp3[j]=dp[i]+1;
            dp3[j]=max(dp3[j],dp3[i]+1);
            dfs2(j,i);
        }
    }
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    bool flag=false;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&ee[i].x,&ee[i].y,&ee[i].w);
        if(ee[i].w==2){
            int x=getFather(ee[i].x);
            int y=getFather(ee[i].y);
            if(x==y){flag=true;break;}
            f[x]=y;
            e[ee[i].x].push_back(ee[i].y);
            e[ee[i].y].push_back(ee[i].x);
        }
        else e[ee[i].x].push_back(ee[i].y);
    }
    if(!flag){
        for(int i=1;i<=n;i++){
            if(!dfn[i])tarjan(i);
        }
        for(int i=0;i<m;i++){
            if(res[ee[i].x]==res[ee[i].y]&&ee[i].w==1){
                flag=true;break;
            }
        }
    }
    if(flag)printf("Infinite\n");
    else{
        int finally=0;
        for(int i=1;i<=n;i++){
            for(int j:e[i]){
                if(res[i]!=res[j])
                    v[res[i]].push_back(res[j]);
                else
                    vv[i].push_back(j);
            }
        }
        toposort(cnt);
        for(int i=1;i<=n;i++)
            s[res[i]].push_back(i);
        for(int i=cnt-1;i>=0;i--){
            int ii=ans[i];
            for(int j:s[ii]){
                for(int k:e[j]){
                    if(res[k]!=ii)
                        dp[j]=max(dp[j],dp[k]+1);
                }
            }
            dfs1(s[ii][0],0);
            dfs2(s[ii][0],0);
            for(int j:s[ii]){
                dp[j]=max(dp[j],dp3[j]);
                finally=max(finally,max(dp[j],dp3[j]));
            }
        }
        printf("%d\n",finally);
    }
}
accuracy: 1
time_ms: 50
memory_kb: 95016
final_rank: 5

code_snippet: #include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 1000001
int dfn[MAXN], low[MAXN], stack[MAXN];
int res[MAXN];
bool flag[MAXN];
vector<int> e[MAXN];
int cur, top, cnt;//cur为访问标号，top为栈顶，cnt为强连通分量个数
//使用前清空dfn,flag数组，cur，cnt置0；返回res存储每个点所在强连通分量集合
void tarjan(int i)
{
    low[i] = dfn[i] = ++cur;
    stack[++top] = i; flag[i] = true;
    for (unsigned j = 0; j < e[i].size(); j++){
        int id = e[i][j];
        if (!dfn[id]){
            tarjan(id);
            low[i] = min(low[i], low[id]);
        }
        else if (flag[id])
            low[i] = min(low[i], dfn[id]);//此处可写low
    }
    if (low[i] == dfn[i]){
        cnt++;
        int t;
        do{
            t = stack[top--];
            res[t] = cnt;
            flag[t] = false;
        } while (t != i);
    }
}

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<int> v[1000001];
int degree[1000001];
int ans[1000001], layer[1000001];//ans为拓扑序列，layer为每个结点层数
//返回值为true表示成功，false表示有环
bool toposort(int n)
{
    int k = 0;
    memset(degree + 1, 0, sizeof(int)*n);
    memset(layer + 1, 0, sizeof(int)*n);
    for (int i = 1; i <= n; i++){
        for (unsigned int t = 0; t < v[i].size(); t++)
            degree[v[i][t]]++;
    }
    for (int i = 1; i <= n; i++){
        if (!degree[i])ans[k++] = i;
    }
    for (int j = 0; j < k; j++){
        for (unsigned int t = 0; t < v[ans[j]].size(); t++){
            int i = v[ans[j]][t];
            if (!--degree[i]){
                ans[k++] = i;
                layer[i] = layer[ans[j]] + 1;
            }
        }
    }
    return k == n;
}

vector<int> vv[200001];
vector<int> s[200001];
int f[200001];
bool vis[200001];
int getFather(int i){
    if(!f[i])return i;
    return f[i]=getFather(f[i]);
}
struct Edge{
    int x,y,w;
}ee[200001];
int out[200001];
int dp[200001],dp2[200001],dp3[200001],son[200001];
void dfs1(int i,int fa)
{
    dp2[i]=dp[i];
    for(int j:vv[i]){
        if(j!=fa){
            dfs1(j,i);
            int t=dp[j]+1;
            if(t>dp[i]){dp2[i]=dp[i];dp[i]=t;son[i]=j;}
            else if(t>dp2[i]){dp2[i]=t;}
        }
    }
}
void dfs2(int i,int fa)
{
    for(int j:vv[i]){
        if(j!=fa){
            if(j==son[i])dp3[j]=dp2[i]+1;
            else dp3[j]=dp[i]+1;
            dp3[j]=max(dp3[j],dp3[i]+1);
            dfs2(j,i);
        }
    }
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2){
    bool flag=false;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&ee[i].x,&ee[i].y,&ee[i].w);
        if(ee[i].w==2){
            int x=getFather(ee[i].x);
            int y=getFather(ee[i].y);
            if(x==y){flag=true;break;}
            f[x]=y;
            e[ee[i].x].push_back(ee[i].y);
            e[ee[i].y].push_back(ee[i].x);
        }
        else e[ee[i].x].push_back(ee[i].y);
    }
    if(!flag){
        for(int i=1;i<=n;i++){
            if(!dfn[i])tarjan(i);
        }
        for(int i=0;i<m;i++){
            if(res[ee[i].x]==res[ee[i].y]&&ee[i].w==1){
                flag=true;break;
            }
        }
    }
    if(flag)printf("Infinite\n");
    else{
        int finally=0;
        for(int i=1;i<=n;i++){
            for(int j:e[i]){
                if(res[i]!=res[j])
                    v[res[i]].push_back(res[j]);
                else
                    vv[i].push_back(j);
            }
        }
        toposort(cnt);
        for(int i=1;i<=n;i++)
            s[res[i]].push_back(i);
        for(int i=cnt-1;i>=0;i--){
            int ii=ans[i];
            for(int j:s[ii]){
                for(int k:e[j]){
                    if(res[k]!=ii)
                        dp[j]=max(dp[j],dp[k]+1);
                }
            }
            dfs1(s[ii][0],0);
            dfs2(s[ii][0],0);
            for(int j:s[ii]){
                dp[j]=max(dp[j],dp3[j]);
                finally=max(finally,max(dp[j],dp3[j]));
            }
        }
        printf("%d\n",finally);
    }
}
}
accuracy: 0.10810810810810811
time_ms: 40
memory_kb: 94056
final_rank: 10

code_snippet: // AOJ #1374 Animal Companion in Maze
// 2025.4.30

#include <bits/stdc++.h>
using namespace std;

#define gc() getchar_unlocked()

int Cin() {
	int n = 0, c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

const int MAXV = 1000005;
const int MAXN = 100005;

int Deg[MAXV], Q[MAXV], Dp[MAXV];
vector<int> E[MAXV], G[MAXN];
int B1[MAXN], B2[MAXN];
int head = 0, tail = 0;

inline void AE(int a, int b, int w){
    E[a].push_back((b<<1)|w);
}

int main(){
    int n = Cin(), m = Cin();
    int cnt = 2*n;

    for(int i = 0; i < m; i++){
        int a = Cin(), b = Cin(), c = Cin();
        if(c == 1) AE(n + a, b, 1);
        else {
            AE(cnt+1, cnt+4, 1);
            AE(cnt+3, cnt+2, 1);
            G[a].push_back(cnt+1);
            G[b].push_back(cnt+3);
            cnt += 4;
        }
    }

    for(int i = 1; i <= n; i++){
        AE(i, i+n, 0);
        int sz = G[i].size();
        if(!sz) continue;
        B1[i] = cnt + 1;
        for(int j = 0; j < sz; j++){
            cnt++;
            AE(cnt, G[i][j], 0);
            if(j) AE(cnt, cnt-1, 0);
        }
        B2[i] = cnt + 1;
        for(int j = sz - 1; j >= 0; j--){
            cnt++;
            AE(cnt, G[i][j], 0);
            if(j != sz-1) AE(cnt, cnt-1, 0);
        }
        for(int j = 0; j < sz; j++){
            int s = G[i][j];
            AE(i, s, 0);
            AE(s+1, n + i, 0);
            if(j)         AE(s+1, B1[i] + j - 1, 0);
            if(j != sz-1) AE(s+1, B2[i] + (sz - j - 2), 0);
        }
    }

    for(int v = 1; v <= cnt; v++){
        for(int x : E[v]){
            int to = x >> 1;
            Deg[to]++;
        }
    }
    for(int v = 1; v <= cnt; v++) if(Deg[v] == 0) Q[++tail] = v;

    int ans = 0;
    while(head < tail){
        int v = Q[++head];
        ans = max(ans, Dp[v]);
        for(int x : E[v]){
            int to = x >> 1, w = x & 1;
            Deg[to]--;
            Dp[to] = max(Dp[to], Dp[v] + w);
            if(Deg[to] == 0) Q[++tail] = to;
        }
    }
    if(tail != cnt) cout << "Infinite" << endl;
    else cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 73044
final_rank: 6

code_snippet: // AOJ #1374 Animal Companion in Maze
// 2025.4.30

#include <bits/stdc++.h>
using namespace std;

#define gc() getchar_unlocked()

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

int main(){
    int n = Cin(), m = Cin();
    vector<int> x(m), y(m), w(m);
    for(int i=0; i<m; i++){
        x[i] = Cin()-1, y[i] = Cin()-1, w[i] = gc() & 0xf, gc();
    }

    vector<int> t, u, p;
    t.reserve(2*m); u.reserve(2*m); p.reserve(2*m);
    for(int i=0; i<m; i++){
        if(w[i]==1){
            t.push_back(x[i]);
            u.push_back(y[i]);
            p.push_back(i);
        } else {
            t.push_back(x[i]);
            u.push_back(y[i]);
            p.push_back(i);
            t.push_back(y[i]);
            u.push_back(x[i]);
            p.push_back(i);
        }
    }
    int M = t.size();
    vector<int> indeg(n,0);
    for(int i=0; i<M; i++) indeg[u[i]]++;
    vector<vector<int>> o1(n), o2(n);
    for(int i=0; i<M; i++){
        int v = t[i];
        if(w[p[i]]==2) o2[v].push_back(i);
        else           o1[v].push_back(i);
    }
    vector<int> c = indeg;
    vector<char> vis(M,0);
    vector<int> topo; topo.reserve(M);
    deque<int> q;
    for(int v=0; v<n; v++){
        if(c[v]==0){
            for(int j:o1[v]) q.push_back(j);
        } else if(c[v]==1){
            for(int j:o2[v]) q.push_back(j);
        }
    }
    while(!q.empty()){
        int i = q.front(); q.pop_front();
        if(vis[i]) continue;
        vis[i]=1;
        topo.push_back(i);
        int v = u[i];
        if(--c[v] == 1) {
            for(int j:o2[v]) if(!vis[j]) q.push_back(j);
        } else if(c[v] == 0) {
            for(int j:o1[v]) if(!vis[j]) q.push_back(j);
        }
    }
    if ((int)topo.size() < M) {
        cout << "Infinite" << endl;
        return 0;
    }
    vector<int> dp(M), mx1(n,0), mx2(n,0), id1(n,-1);
    for(int k=M-1; k>=0; k--){
        int i = topo[k];
        int v = u[i], d = p[i];
        int best = (id1[v]!=d ? mx1[v] : mx2[v]);
        dp[i] = best + 1;
        int v2 = t[i];
        if(dp[i] > mx1[v2]){
            mx2[v2] = mx1[v2];
            mx1[v2] = dp[i];
            id1[v2] = d;
        } else if(id1[v2]!=d && dp[i] > mx2[v2]) mx2[v2] = dp[i];
    }
    int ans = 0;
    for(int i=0; i<M; i++) ans = max(ans, dp[i]);
    cout << ans << endl;
    return 0;
}
accuracy: 0.08108108108108109
time_ms: 10
memory_kb: 17704
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<pair<int,int>>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> md(n+m+m, 0); // 到這個點的最大值

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {

        int u = s[0];

        auto dfs = [&](auto self, int cur, int par, int d) -> void { // (max_depth, node)
            md[cur] = max(md[cur], d);
            if(md[cur] > md[u]) u = cur;
            for(auto [x, w] : adj2[cur]) if(x != par) {
                self(self, x, cur, d+w);
            }
        };
        // cout << "u:" << u << endl;
        dfs(dfs, u, u, 0);
        // cout << "u:" << u << endl;
        // cout << endl;
        dfs(dfs, u, u, 0);
        // cout << endl;
        dfs(dfs, u, u, 0);
        // cout << endl;
    };
    

    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].emplace_back(u, 1);
            }
        }
        
        // for(int j = 0; j < adj2.size(); j++) {
        //     cout << j << " -> ";
        //     for(auto [x, _] : adj2[j]) cout << x << ", ";
        //     cout << endl;
        // }
        // cout << "------\n";
        
        cal(dg[i]);
        for(int x : dg[i]) {
        for(auto u : adj[x]) if(!ins[u]) {
            tot++;
            adj2[tot].emplace_back(u, md[x]+1);
            adj2[u].emplace_back(tot, md[x]+1);
        }
    }
        
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n + m; i++) {
    //     cout << i << ": " << md[i] << endl;
    // }
    // cout << tot << endl;
    cout << *max_element(md.begin(), md.begin()+n) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 1
time_ms: 50
memory_kb: 30716
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<pair<int,int>>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> md(n+m, 0); // 到這個點的最大值

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(auto [x, w] : adj2[u]) if(x != par) {
                res = max(res, self(self, x, u, d+w));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            md[u] = max(md[u], d);
            for(auto [x, w] : adj2[u]) if(x != par) {
                self(self, x, u, d+w);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
    };
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].emplace_back(u, 1);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    tot++;
                    adj2[tot].emplace_back(u, md[x]+1);
                    adj2[u].emplace_back(tot, md[x]+1);
                }
            }
        }
        
        cal(dg[i]);
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n + m; i++) {
    //     cout << i << ": " << md[i] << endl;
    // }
    cout << *max_element(md.begin(), md.begin()+n) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25300
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<pair<int,int>>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> md(n+m, 0); // 到這個點的最大值

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(auto [x, w] : adj2[u]) if(x != par) {
                res = max(res, self(self, x, u, d+w));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            md[u] = max(md[u], d);
            for(auto [x, w] : adj2[u]) if(x != par) {
                self(self, x, u, d+w);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
    };
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].emplace_back(u, 1);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    tot++;
                    adj2[tot].emplace_back(u, md[x]+1);
                    adj2[u].emplace_back(tot, md[x]+1);
                }
            }
        }
        
        cal(dg[i]);
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n + m; i++) {
    //     cout << i << ": " << md[i] << endl;
    // }
    cout << *max_element(md.begin(), md.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25300
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> w(n+m, 1); // 從點i出發的權重
    vector<int> ans(n+m, 1);

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj2[u]) if(x != par) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            // cout << u << ' ';
            ans[u] = max(ans[u], d);
            for(int x : adj2[u]) if(x != par) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
        // cout << endl;

        // cout << u << ' ' << v << endl;

        for(auto x : s) w[x] = ans[x];
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].push_back(u);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    tot++;
                    w[tot] = w[x];
                    adj2[tot].push_back(u);
                    adj2[u].push_back(tot);
                }
            }
        }
        // for(int j = 0; j < n; j++) {
        //     cout << j+1 << "->";
        //     for(int u : adj2[j]) cout << u+1 << ", ";
        //     cout << endl;
        // }
        
        cal(dg[i]);
        // cout << "-----\n";
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n; i++) {
    //     cout << w[i] << ' ';
    // }
    // cout << endl;
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25972
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> w(n, 1); // 從點i出發的權重
    vector<int> ans(n, 1);

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj2[u]) if(x != par) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            // cout << u << ' ';
            ans[u] = max(ans[u], d);
            for(int x : adj2[u]) if(x != par) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
        // cout << endl;

        // cout << u << ' ' << v << endl;

        for(auto x : s) w[x] = ans[x];
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].push_back(u);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    tot++;
                    adj2[tot].push_back(u);
                    adj2[u].push_back(tot);
                }
            }
        }
        // for(int j = 0; j < n; j++) {
        //     cout << j+1 << "->";
        //     for(int u : adj2[j]) cout << u+1 << ", ";
        //     cout << endl;
        // }
        
        cal(dg[i]);
        // cout << "-----\n";
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n; i++) {
    //     cout << w[i] << ' ';
    // }
    // cout << endl;
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25556
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> w(n, 1); // 從點i出發的權重
    vector<int> ans(n, 1);

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj2[u]) if(ins[u] && x != par) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            // cout << u << ' ';
            ans[u] = max(ans[u], d);
            for(int x : adj2[u]) if(ins[u] && x != par) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
        // cout << endl;

        // cout << u << ' ' << v << endl;

        for(auto x : s) w[x] = ans[x];
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].push_back(u);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    tot++;
                    adj2[tot].push_back(u);
                    adj2[u].push_back(tot);
                }
            }
        }
        // for(int j = 0; j < n; j++) {
        //     cout << j+1 << "->";
        //     for(int u : adj2[j]) cout << u+1 << ", ";
        //     cout << endl;
        // }
        
        cal(dg[i]);
        // cout << "-----\n";
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n; i++) {
    //     cout << w[i] << ' ';
    // }
    // cout << endl;
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25440
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> adj2(n+m);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> w(n, 1); // 從點i出發的權重
    vector<int> ans(n, 1);

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj2[u]) if(ins[u] && x != par) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            // cout << u << ' ';
            ans[u] = max(ans[u], d);
            for(int x : adj2[u]) if(ins[u] && x != par) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
        // cout << endl;

        // cout << u << ' ' << v << endl;

        for(auto x : s) w[x] = ans[x];
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    int tot = n-1;
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].push_back(u);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                tot++;
                for(auto u : adj[x]) if(ins[u]) {
                    adj2[tot].push_back(u);
                    adj2[u].push_back(tot);
                }
            }
        }
        // for(int j = 0; j < n; j++) {
        //     cout << j+1 << "->";
        //     for(int u : adj2[j]) cout << u+1 << ", ";
        //     cout << endl;
        // }
        
        cal(dg[i]);
        // cout << "-----\n";
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n; i++) {
    //     cout << w[i] << ' ';
    // }
    // cout << endl;
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 25700
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    vector<vector<int>> dg;
    scc(adj, [&](vi & v) { 
        compsize[ncomps] = sz(v); 
        dg.push_back(v);
    });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> adj2(n);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else {
                bi_cnt[comp[u]]++; // 計算scc雙向邊數量
            }
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }


    vector<int> w(n, 1); // 從點i出發的權重
    vector<int> ans(n, 1);

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj2[u]) if(ins[u] && x != par) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            // cout << u << ' ';
            ans[u] = max(ans[u], d);
            for(int x : adj2[u]) if(ins[u] && x != par) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);
        // cout << endl;

        // cout << u << ' ' << v << endl;

        for(auto x : s) w[x] = ans[x];
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    
    for(int i = ncomps - 1; i >= 0; i--) {
        for(int x : dg[i]) ins[x] = 1;
        for(int x : dg[i]) {
            for(auto u : adj[x]) if(ins[x] && ins[u]) {
                adj2[x].push_back(u);
            }
        }
        if(i + 1 != ncomps) {
             for(int x : dg[i+1]) {
                for(auto u : adj[x]) if(ins[u]) {
                    w[u] = max(w[u], w[x]+1);
                }
            }
        }
        // for(int j = 0; j < n; j++) {
        //     cout << j+1 << "->";
        //     for(int u : adj2[j]) cout << u+1 << ", ";
        //     cout << endl;
        // }
        
        cal(dg[i]);
        // cout << "-----\n";
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
        for(auto x : dg[i]) adj2[x].clear();
        for(auto x : dg[i]) ins[x] = 0;
    }
    // for(int i = 0; i < n; i++) {
    //     cout << w[i] << ' ';
    // }
    // cout << endl;
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1
*/
accuracy: 0.08108108108108109
time_ms: 40
memory_kb: 22368
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

/**
 * Author: Lukas Polacek
 * Date: 2009-10-28
 * License: CC0
 * Source: Czech graph algorithms book, by Demel. (Tarjan's algorithm)
 * Description: Finds strongly connected components in a
 * directed graph. If vertices $u, v$ belong to the same component,
 * we can reach $u$ from $v$ and vice versa.
 * Usage: scc(graph, [\&](vi\& v) { ... }) visits all components
 * in reverse topological order. comp[i] holds the component
 * index of a node (a component only has edges to components with
 * lower index). ncomps will contain the number of components.
 * Time: O(E + V)
 * Status: Bruteforce-tested for N <= 5
 */

vi val, comp, z, cont;
int Time, ncomps;
template<class G, class F> int dfs(int j, G& g, F& f) {
	int low = val[j] = ++Time, x; z.push_back(j);
	for (auto e : g[j]) if (comp[e] < 0)
		low = min(low, val[e] ?: dfs(e,g,f));

	if (low == val[j]) {
		do {
			x = z.back(); z.pop_back();
			comp[x] = ncomps;
			cont.push_back(x);
		} while (x != j);
		f(cont); cont.clear();
		ncomps++;
	}
	return val[j] = low;
}
template<class G, class F> void scc(G& g, F f) {
	int n = sz(g);
	val.assign(n, 0); comp.assign(n, -1);
	Time = ncomps = 0;
	rep(i,0,n) if (comp[i] < 0) dfs(i, g, f);
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin.exceptions(cin.failbit);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n);
    vector<tuple<int, int, int>> edge;

    
    for(int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--, v--;
        adj[u].push_back(v);
        if(w == 2) adj[v].push_back(u);
        edge.emplace_back(u, v, w);
    }

    // scc 每一個點i給予scc編號comp[i]
    vi compsize(n);
    scc(adj, [&](vi & v) { compsize[ncomps] = sz(v); });
    vector<vector<int>> t_adj(ncomps);

    // 建scc的邊，順便檢查環。
    vector<int> bi_cnt(ncomps);
    vector<vector<int>> dg(ncomps);
    bool ok = true;
    for(auto [u, v, w] : edge) {
        if(comp[u] != comp[v]) {
            t_adj[comp[u]].push_back(comp[v]);
            dg[comp[v]].push_back(u);
        } else {
            if(w == 1) ok = false;  // scc有單向邊->有環
            else bi_cnt[comp[u]]++; // 計算scc雙向邊數量
        }
    }
    
    for(int i = 0; i < ncomps; i++) {
        if(bi_cnt[i] >= compsize[i]) ok = false;
    }
    if(ok == false) {
        cout << "Infinite\n";
        return 0;
    }

    for(int i = 0; i < n; i++) dg[comp[i]].push_back(i);

    vector<int> w(n, 1); // 從點i出發的權重

    // 對點集合s做樹上每個點的最遠距離
    vector<int> ins(n);
    auto cal = [&](vector<int> &s) {
        for(int x : s) ins[x] = 1;
        // cout << "s: "; for(int x : s) cout << x << ' '; cout << endl;

        int u, v;

        auto dfs1 = [&](auto self, int u, int par, int d) -> pair<int, int> { // (max_depth, node)
            pair<int, int> res = {d, u};
            for(int x : adj[u]) if(x != par && ins[x] && ins[u]) {
                res = max(res, self(self, x, u, d+w[u]));
            }
            return res;
        };
        u = dfs1(dfs1, s[0], s[0], 0).second;
        v = dfs1(dfs1, u, u, 0).second;

        auto dfs2 = [&](auto self, int u, int par, int d) -> void { // (max_depth, node)
            w[u] = max(w[u], d);
            for(int x : adj[u]) if(x != par && ins[x] && ins[u]) {
                self(self, x, u, d+w[u]);
            }
        };
        dfs2(dfs2, u, u, 0);
        dfs2(dfs2, v, v, 0);

        // cout << u << ' ' << v << endl;

        for(auto x : s) ins[x] = 0;
    };
    
    
    

    // for(int i = 0; i < ncomps; i++) {
    //     cout << i << ": " << compsize[i] << "," << bi_cnt[i] << endl;
    // }


    // for(int i = 0; i < n; i++) {
    //     cout << i+1 << " -> " << comp[i] << endl;
    // }
    

    vector<int> dp(ncomps, 1);
    for(int i = ncomps - 1; i >= 0; i--) {
        cal(dg[i]);
        // for(int u : t_adj[i]) {
        //     // cout << "i to u: " << i << "->" << u << endl;
        //     dp[u] = max(dp[u], dp[i] + 1);
        // }
    }
    cout << *max_element(w.begin(), w.end()) << endl;
}


/*
6 7 
1 3 2 
3 2 1 
3 5 1 
3 6 2 
4 3 1 
4 6 1 
5 2 1



*/
accuracy: 0.08108108108108109
time_ms: 30
memory_kb: 19984
final_rank: 13

code_snippet: #include <bits/stdc++.h>

#define rep(i, s, n) for (int i = (int)(s); i < (int)(n); i++)
#define rrep(i, s, n) for (int i = (int)(n)-1; i >= (int)(s); i--)
#define all(v) v.begin(), v.end()

using ll = long long;
using ld = long double;
using ull = unsigned long long;

template <typename T> bool chmin(T &a, const T &b) {
    if (a <= b) return false;
    a = b;
    return true;
}
template <typename T> bool chmax(T &a, const T &b) {
    if (a >= b) return false;
    a = b;
    return true;
}

using namespace std;

const int inf = 1e9;

int op(int a, int b){
	return max(a,b);
}

int e(){
	return -inf;
}

template<class S, S (*op)(S, S), S(*e)()> struct segtree{
	private:
		int n;
		int sz;
		vector<S> data;
		void update(int i){
			data[i] = op(data[2*i], data[2*i+1]);
		}
	public:
		segtree(int n): segtree(vector<S>(n, e())){}
		segtree(const vector<S> &v) : n((int)v.size()), sz(1) {
			while(sz<n)sz*=2;
			data=vector<S>(2*sz,e());
			rep(i,0,n)data[sz+i]=v[i];
			rrep(i,1,sz)update(i);
		}

		void set(int p, S x){
			assert(0<=p&&p<n);
			p+=sz;
			data[p]=x;
			while(p>1){
				p>>=1;
				update(p);
			}
		}
		S get(int p){
			assert(0<=p&&p<n);
			return data[p+sz];
		}
		S prod(int l, int r){
			assert(0<=l&&l<=r&&r<=n);
			S sml=e(), smr=e();
			l+=sz;
			r+=sz;
			while(l<r){
				if(l&1)sml=op(sml,data[l++]);
				if(r&1)smr=op(data[--r],smr);
				l>>=1;
				r>>=1;
			}
			return op(sml, smr);
		}
		S all_prod(){
			return data[1];
		}
		template<class F> int max_right(int l, F f){
			assert(0<=l&&l<=n);
			assert(f(e()));
			if(l==n)return n;
			l+=sz;
			S sm = e();
			do {
				while(l%2==0)l>>=1;
				if(!f(op(sm,data[l]))){
					while(l<sz){
						l=2*l;
						if(f(op(sm,data[l]))){
							sm=op(sm,data[l]);
							l++;
						}
					}
					return l-sz;
				}
				sm=op(sm,data[l]);
				l++;
			}while((l&-l)!=l);
			return n;
		}

};

int main(){
	int n, m; cin >> n >> m;
	vector ikeru(n, vector<pair<int,int>>(0));
	rep(i,0,m){
		int x, y;
		int w;
		cin >> x >> y >> w;
		x--; y--;
		ikeru[x].push_back(pair(y,i));
		if (w == 2){
			ikeru[y].push_back(pair(x,i));
		}
	}
	
	vector<map<int,int>> taio(n);
	rep(i,0,n){
		int piv = 0;
		for (auto[j,c]: ikeru[i]){
			taio[i][c] = piv;
			piv++;
		}
	}

	vector<segtree<int,op,e>> seg;
	rep(i,0,n){
		seg.push_back(segtree<int,op,e>(vector<int>((int)ikeru[i].size(), inf)));
	}
	vector<map<int,int>> mp(n);

	auto f = [&](int x){
		return x < inf;
	};

	vector<bool> seen(n);
	bool mode = true;

	auto calc = [&](auto self, int i, int j) -> int {
		if (seen[i]){
			mode = false;
			return -1;
		}


		if (mp[i].find(j) != mp[i].end()) return mp[i][j];
		int ret = 0;

		seen[i] = 1;

		if ((int)ikeru[i].size() == 0){
			ret = 0;
		}else if (taio[i].find(j) == taio[i].end()){
			int piv = 0;
			while(piv < (int)ikeru[i].size()){
				int d = seg[i].max_right(piv, f);
				if (d == (int)ikeru[i].size()) break;
				assert(seg[i].get(d) == inf);
				int tar = self(self, ikeru[i][d].first, ikeru[i][d].second);
				seg[i].set(d, tar);
				if (!mode){
					return -1;
				}
				piv = d;
			}
			if (!mode){
				return -1;
			}
			ret = seg[i].all_prod() + 1;
		}else{
			int val = taio[i][j];
			int piv = 0;
			while(piv < (int)ikeru[i].size()){
				int d = seg[i].max_right(piv, f);
				if (d == (int)ikeru[i].size()) break;
				assert(seg[i].get(d) == inf);
				if (d == val){
					piv++;
					continue;
				}
				int tar = self(self, ikeru[i][d].first, ikeru[i][d].second);
				seg[i].set(d, tar);
				if (!mode){
					return -1;
				}
				piv = d;
			}
			if ((int)ikeru[i].size() >= 2){
				ret = op(seg[i].prod(0, val), seg[i].prod(val+1, (int)ikeru[i].size())) + 1;
			}else{
				ret = 0;
			}
		}

		if (!mode){
			return -1;
		}

		seen[i] = 0;
		mp[i][j] = ret;
		return ret;
	};

	int ans = 0;
	rep(i,0,n){
		chmax(ans, calc(calc,i,-1));
		if (!mode){
			cout << "Infinite\n";
			return 0;
		}
	}
	
	cout << ans << '\n';
}
accuracy: 1
time_ms: 190
memory_kb: 60580
final_rank: 7

code_snippet: #include<iostream>
#include<vector>
#include<deque>
#include<cstdlib>

#include <algorithm>
#include <cassert>
#include <vector>


#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

constexpr int bsf_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  public:
    segtree() : segtree(0) {}
    explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
    explicit segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) const {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() const { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) const {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) const {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) const {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) const {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

using namespace std;
int op(int a,int b){return max(a,b);}
int e(){return 0;}
vector<int>TO,rev,inv;
vector<int>EI[1<<17];
vector<int>memo;
atcoder::segtree<int,op,e>seg[1<<17];
deque<int>rest[1<<17];
int solve(int ei)
{
	int u=TO[ei];
	while(!rest[u].empty())
	{
		int id=rest[u].front();
		if(id==rev[ei])break;
		rest[u].pop_front();
		seg[u].set(id,(int)1e9);
		int r=solve(EI[u][id]);
		seg[u].set(id,r);
	}
	while(!rest[u].empty())
	{
		int id=rest[u].back();
		if(id==rev[ei])break;
		rest[u].pop_back();
		seg[u].set(id,(int)1e9);
		int r=solve(EI[u][id]);
		seg[u].set(id,r);
	}
	int now;
	if(rev[ei]==-1)now=seg[u].all_prod();
	else now=op(seg[u].prod(0,rev[ei]),seg[u].prod(rev[ei]+1,EI[u].size()));
	if(now==(int)1e9)
	{
		cout<<"Infinite"<<endl;
		exit(0);
	}
	return memo[ei]=now+1;
}
int main()
{
	int N,M;
	cin>>N>>M;
	for(int i=0;i<M;i++)
	{
		int x,y,w;cin>>x>>y>>w;
		TO.push_back(y);
		EI[x].push_back(TO.size()-1);
		rest[x].push_back(EI[x].size()-1);
		inv.push_back(EI[x].size()-1);
		if(w==1)rev.push_back(-1);
		else
		{
			TO.push_back(x);
			EI[y].push_back(TO.size()-1);
			rest[y].push_back(EI[y].size()-1);
			inv.push_back(EI[y].size()-1);
			rev.push_back(EI[y].size()-1);
			rev.push_back(EI[x].size()-1);
		}
	}
	for(int i=1;i<=N;i++)seg[i]=atcoder::segtree<int,op,e>(vector<int>(EI[i].size(),-1));
	memo=vector<int>(TO.size(),-1);
	int ans=0;
	for(int i=0;i<TO.size();i++)
	{
		if(memo[i]==-1)solve(i);
		ans=max(ans,memo[i]);
	}
	cout<<ans<<endl;
}
accuracy: 1
time_ms: 140
memory_kb: 119176
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

int get_id(int i,bool f){
    return 2*i+f;
}

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void either(int i,bool f,int j,bool g){
    add_edge(get_id(i,!f),get_id(j,g));
    add_edge(get_id(j,!g),get_id(i,f));
    //add_edge(2*i+(!f),2*j+g);
    //add_edge(2*j+(!g),2*i+f);
}

void imply(int i,bool f,int j,bool g){
    either(i,!f,j,g);
}
//iがfならばjがg

void must(int i,bool f){
    either(i,f,i,f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

void init(int sz){
    V=sz;
    for(int i=0;i<V;i++){
        cmp[i]=0;
        G[i].clear();
        rG[i].clear();
        used[i]=false;
    }
    vs.clear();
}

struct UF{
    int n;
    vector<int> par,size,edge;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        edge.assign(n,0);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        edge[root(a)]++;
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            edge[root(a)]+=edge[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

int dp[MAX];
int ma[MAX];

vector<int> GG[MAX];

void make(int u,int p){
    chmax(ma[u],dp[u]);
    for(int to:GG[u]){
        if(to==p) continue;
        make(to,u);
        chmax(ma[u],ma[to]+1);
    }
}

void DFS(int u,int p){
    
    int ma1=dp[u],ma2=-INF;
    
    chmax(dp[u],ma[u]);
    
    for(int to:GG[u]){
        if(ma1<ma[to]+1){
            ma2=ma1;
            ma1=ma[to]+1;
        }else{
            chmax(ma2,ma[to]+1);
        }
    }
    
    for(int to:GG[u]){
        if(to==p) continue;
        
        int a=ma[u],b=ma[to];
        
        if(ma1==ma[to]+1){
            ma[u]=ma2;
        }else{
            ma[u]=ma1;
        }
        chmax(ma[to],ma[u]+1);
        
        DFS(to,u);
        
        ma[u]=a;
        ma[to]=b;
    }
}

vector<int> GGG[MAX];

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    V=N;
    
    UF uf;uf.init(N);
    vector<int> mita(N),hen(N),incn(N),cn(N);
    vector<tuple<int,int,int>> E(M);
    for(int i=0;i<M;i++){
        int a,b,c;cin>>a>>b>>c;a--;b--;
        E[i]={a,b,c};
        if(c==2){
            if(uf.check(a,b)){
                cout<<"Infinite\n";
                return 0;
            }
            uf.unite(a,b);
            GG[a].push_back(b);
            GG[b].push_back(a);
        }
    }
    
    for(int i=0;i<M;i++){
        auto [a,b,c]=E[i];
        if(c==1){
            GGG[a].push_back(b);
            a=uf.root(a);
            b=uf.root(b);
            if(a==b){
                cout<<"Infinite\n";
                return 0;
            }
            add_edge(a,b);
        }
    }
    
    int K=scc();
    
    if(K<N){
        cout<<"Infinite\n";
        return 0;
    }
    
    vector<vector<int>> gro(N);
    for(int i=0;i<N;i++){
        gro[uf.root(i)].push_back(i);
    }
    
    reverse(all(vs));
    
    for(int x:vs){
        if(si(gro[x])){
            make(x,-1);
            DFS(x,-1);
            
            for(int z:gro[x]){
                used[z]=true;
                for(int to:GGG[z]){
                    chmax(dp[to],dp[z]+1);
                }
            }
        }
    }
    
    int ans=-1;
    for(int i=0;i<N;i++) chmax(ans,dp[i]);
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 50
memory_kb: 51932
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

int get_id(int i,bool f){
    return 2*i+f;
}

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void either(int i,bool f,int j,bool g){
    add_edge(get_id(i,!f),get_id(j,g));
    add_edge(get_id(j,!g),get_id(i,f));
    //add_edge(2*i+(!f),2*j+g);
    //add_edge(2*j+(!g),2*i+f);
}

void imply(int i,bool f,int j,bool g){
    either(i,!f,j,g);
}
//iがfならばjがg

void must(int i,bool f){
    either(i,f,i,f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

void init(int sz){
    V=sz;
    for(int i=0;i<V;i++){
        cmp[i]=0;
        G[i].clear();
        rG[i].clear();
        used[i]=false;
    }
    vs.clear();
}

struct UF{
    int n;
    vector<int> par,size,edge;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        edge.assign(n,0);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        edge[root(a)]++;
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            edge[root(a)]+=edge[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

int dp[MAX];
int ma[MAX];

vector<int> GG[MAX];

vector<int> use;

void make(int u,int p){
    use.push_back(u);
    chmax(ma[u],dp[u]);
    for(int to:GG[u]){
        if(to==p) continue;
        make(to,u);
        chmax(ma[u],ma[to]+1);
    }
}

void DFS(int u,int p){
    
    int ma1=dp[u],ma2=-INF;
    
    chmax(dp[u],ma[u]);
    
    for(int to:GG[u]){
        if(ma1<ma[to]+1){
            ma2=ma1;
            ma1=ma[to]+1;
        }else{
            chmax(ma2,ma[to]+1);
        }
    }
    
    for(int to:GG[u]){
        if(to==p) continue;
        
        int a=ma[u],b=ma[to];
        
        if(ma1==ma[to]+1){
            ma[u]=ma2;
        }else{
            ma[u]=ma1;
        }
        chmax(ma[to],ma[u]+1);
        
        DFS(to,u);
        
        ma[u]=a;
        ma[to]=b;
    }
}

vector<int> GGG[MAX];

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    V=N;
    
    UF uf;uf.init(N);
    vector<int> mita(N),hen(N),incn(N),cn(N);
    vector<tuple<int,int,int>> E(M);
    for(int i=0;i<M;i++){
        int a,b,c;cin>>a>>b>>c;a--;b--;
        E[i]={a,b,c};
        if(c==2){
            if(uf.check(a,b)){
                cout<<"Infinite\n";
                return 0;
            }
            uf.unite(a,b);
            GG[a].push_back(b);
            GG[b].push_back(a);
        }
    }
    
    for(int i=0;i<M;i++){
        auto [a,b,c]=E[i];
        if(c==1){
            GGG[a].push_back(b);
            a=uf.root(a);
            b=uf.root(b);
            if(a==b){
                cout<<"Infinite\n";
                return 0;
            }
            //GGG[a].push_back(b);
            add_edge(a,b);
        }
    }
    
    int K=scc();
    
    if(K<N){
        cout<<"Infinite\n";
        return 0;
    }
    
    vector<vector<int>> gro(N);
    for(int i=0;i<N;i++){
        gro[uf.root(i)].push_back(i);
    }
    
    reverse(all(vs));
    
    for(int x:vs){
        if(si(gro[x])){
            //use.clear();
            make(x,-1);
            DFS(x,-1);
            
            //mita[uf.root(x)]=true;
            
            for(int z:gro[x]){
                used[z]=true;
                for(int to:GGG[z]){
                    chmax(dp[to],dp[z]+1);
                    //cn[uf.root(to)]++;
                }
            }
        }
    }
    
    int ans=-1;
    for(int i=0;i<N;i++) chmax(ans,dp[i]);
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 40
memory_kb: 52428
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

int get_id(int i,bool f){
    return 2*i+f;
}

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void either(int i,bool f,int j,bool g){
    add_edge(get_id(i,!f),get_id(j,g));
    add_edge(get_id(j,!g),get_id(i,f));
    //add_edge(2*i+(!f),2*j+g);
    //add_edge(2*j+(!g),2*i+f);
}

void imply(int i,bool f,int j,bool g){
    either(i,!f,j,g);
}
//iがfならばjがg

void must(int i,bool f){
    either(i,f,i,f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

void init(int sz){
    V=sz;
    for(int i=0;i<V;i++){
        cmp[i]=0;
        G[i].clear();
        rG[i].clear();
        used[i]=false;
    }
    vs.clear();
}

struct UF{
    int n;
    vector<int> par,size,edge;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        edge.assign(n,0);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        edge[root(a)]++;
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            edge[root(a)]+=edge[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

int dp[MAX];
int ma[MAX];

vector<int> GG[MAX];

vector<int> use;

void make(int u,int p){
    use.push_back(u);
    chmax(ma[u],dp[u]);
    for(int to:GG[u]){
        if(to==p) continue;
        make(to,u);
        chmax(ma[u],ma[to]+1);
    }
}

void DFS(int u,int p){
    
    int ma1=dp[u],ma2=-INF;
    
    chmax(dp[u],ma[u]);
    
    for(int to:GG[u]){
        if(ma1<ma[to]+1){
            ma2=ma1;
            ma1=ma[to]+1;
        }else{
            chmax(ma2,ma[to]+1);
        }
    }
    
    for(int to:GG[u]){
        if(to==p) continue;
        
        int a=ma[u],b=ma[to];
        
        if(ma1==ma[to]+1){
            ma[u]=ma2;
        }else{
            ma[u]=ma1;
        }
        chmax(ma[to],ma[u]+1);
        
        DFS(to,u);
        
        ma[u]=a;
        ma[to]=b;
    }
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,M;cin>>N>>M;
    V=N;
    
    UF uf;uf.init(N);
    vector<int> mita(N),hen(N),incn(N),cn(N);
    vector<tuple<int,int,int>> E(M);
    for(int i=0;i<M;i++){
        int a,b,c;cin>>a>>b>>c;a--;b--;
        E[i]={a,b,c};
        if(c==2){
            if(uf.check(a,b)){
                cout<<"Infinite\n";
                return 0;
            }
            uf.unite(a,b);
            GG[a].push_back(b);
            GG[b].push_back(a);
        }
    }
    
    for(int i=0;i<M;i++){
        auto [a,b,c]=E[i];
        if(c==1){
            a=uf.root(a);
            b=uf.root(b);
            if(a==b){
                cout<<"Infinite\n";
                return 0;
            }
            add_edge(a,b);
        }
    }
    
    int K=scc();
    if(K<N){
        cout<<"Infinite\n";
        return 0;
    }
    
    init(N);
    for(int i=0;i<M;i++){
        auto [a,b,c]=E[i];
        if(c==1){
            hen[a]=hen[b]=true;
            incn[uf.root(b)]++;
            add_edge(a,b);
        }
    }
    
    scc();
    
    reverse(all(vs));
    
    for(int x:vs){
        if(incn[uf.root(x)]==cn[uf.root(x)]){
            if(!mita[uf.root(x)]){
                use.clear();
                make(x,-1);
                DFS(x,-1);
                
                mita[uf.root(x)]=true;
                
                for(int z:use){
                    for(int to:G[z]){
                        chmax(dp[to],dp[z]+1);
                        cn[uf.root(to)]++;
                    }
                }
            }
        }
    }
    
    for(int i=0;i<N;i++){
        if(!mita[uf.root(i)]){
            make(i,-1);
            //for(int j=0;j<N;j++) cout<<dp[j]<<" "<<ma[j]<<endl;
            DFS(i,-1);
            mita[uf.root(i)]=true;
        }
    }
    
    int ans=-1;
    for(int i=0;i<N;i++) chmax(ans,dp[i]);
    
    cout<<ans<<endl;
}
accuracy: 0.2972972972972973
time_ms: 40
memory_kb: 41624
final_rank: 9