考察建图的一个最短路问题,因为切换颜色会导致cost+1,因此可以考虑如下建图,对于某一种颜色边构成的一个连通块,新开一个点t,每个连通块内点向t连一条代价为1的边,然后t向连通块内点连一条代价为0的边,此时就可以发现选择走某种颜色就是能用1的代价到达该色的连通块内每个点,之后跑0/1bfs即可。
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define sc second
#define pb push_back
#define ll long long
#define trav(v,x) for(auto v:x)
#define all(x) (x).begin(), (x).end()
#define VI vector<int>
#define VLL vector<ll>
#define pll pair<ll, ll>
#define double long double
//#define int long long
using namespace std;
const int N = 1e6 + 100;
const int inf = 1e9;
//const ll inf = 1e18;
const ll mod = 998244353;//1e9 + 7;
#ifdef LOCAL
void debug_out(){cerr << endl;}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T)
{
cerr << " " << to_string(H);
debug_out(T...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif
void sol()
{
int n, m, num;
cin >> n >> m;
num = n;
vector<tuple<int, int, int>> edge;
for(int i = 0; i < m; i++)
{
int x, y, c;
cin >> x >> y >> c;
--x, --y;
edge.pb(make_tuple(c, x, y));
}
sort(all(edge));
VI fa(n), sz(n);
vector<VI> son(n);
function<int(int)> find = [&](int x)
{
return fa[x] == x ? x : find(fa[x]);
};
VI cur;
vector<vector<pii>> adj(N);
function<void(int)> dfs = [&](int x)
{
cur.pb(x);
trav(v, son[x])
dfs(v);
};
auto gao = [&](int x)
{
cur.clear();
dfs(x);
int nw = num++;
//cerr << "GG" << '\n';
trav(v, cur)
{
//cerr << v << '\n';
adj[v].pb(pii(0, nw));
adj[nw].pb(pii(1, v));
}
//cerr << "FIN" << '\n';
};
for(int l = 0, r; l < m; l = r)
{
r = l;
while(r < m && get<0>(edge[r]) == get<0>(edge[l]))
++r;
for(int i = l; i < r; i++)
{
int c, x, y;
tie(c, x, y) = edge[i];
//cerr << "!!" << c << ' ' << x << ' ' << y << '\n';
fa[x] = x;
fa[y] = y;
son[x].clear();
son[y].clear();
sz[x] = sz[y] = 1;
}
for(int i = l; i < r; i++)
{
int c, x, y;
tie(c, x, y) = edge[i];
int fx = find(x), fy = find(y);
if(fx == fy)
continue;
if(sz[fx] < sz[fy])
fa[fx] = fy, sz[fy] += sz[fx], son[fy].pb(fx);
else fa[fy] = fx, sz[fx] += sz[fy], son[fx].pb(fy);
}
for(int i = l; i < r; i++)
{
int c, x, y;
tie(c, x, y) = edge[i];
if(fa[x] == x)
gao(x), fa[x] = -1;
if(fa[y] == y)
gao(y), fa[y] = -1;
}
}
//cerr << "SSSS" << '\n';
vector<int> dis(num, inf), vis(num, 0);
deque<int> q;
dis[0] = 0;
q.push_back(0);
while(!q.empty())
{
int nw = q.front();
q.pop_front();
if(vis[nw])
continue;
vis[nw] = 1;
sort(all(adj[nw]));
trav(v, adj[nw])
{
int to, d;
tie(d, to) = v;
if(vis[to])
continue;
if(dis[to] > dis[nw])
{
//cerr << nw << ' ' << to << ' ' << d << '\n';
dis[to] = dis[nw] + d;
if(d == 0)
q.push_front(to);
else q.push_back(to);
}
}
}
if(dis[n - 1] == inf)
dis[n - 1] = -1;
cout << dis[n - 1] << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
// int tt;
// cin >> tt;
// while(tt--)
sol();
}