#include<bits/stdc++.h> usingnamespacestd; #define ll long long constint N = 100000 + 123; constint M = 400000 + 223; #define rep(i,from,to) for(int i=(int)(from);i<=(int)(to);++i) structMyIn { template <typename T> MyIn& operator>> (T &x) { x=0;bool s=0;char c=getchar();while(c>'9'||c<'0'){if(c=='-')s=1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}if(s)x=-x;return (*this); } } rin;
#ifdef D voiddbg(){cerr << "\n";} template<typename T, typename... A> void dbg(T a, A... x) {cerr << a << ' '; dbg(x...);} #define logs(x...) {cerr << #x << " -> "; dbg(x);} #else #define logs(...) {} #endif
// tail, weight, index vector<tuple<int, int, int>> g[N]; // head, tail, weight vector<tuple<int, int, int>> edges; int n, m;
ll dist1[N]; ll distn[N]; int pre1[N]; int pren[N]; bool vis[N]; priority_queue<pair<ll, ll>> que; voiddijkstra(int src, ll dist[], int pre[]){ memset(dist, 0x3f, sizeof(ll) * N); memset(vis, 0, sizeof(vis)); dist[src] = 0; que.push(make_pair(0, src)); while (que.size()) { auto [d, u] = que.top(); que.pop(); if (vis[u]) continue; vis[u] = 1; for (auto &[v, w, i]: g[u]) { if (dist[u] + w < dist[v]) { dist[v] = dist[u] + w; que.push(make_pair(-dist[v], v)); // record the index of edge pre[v] = i; } } } }
int on_shortest[N]; // if a vertex is on the shortest path, then its index. o/w 0 bool edge_on_shortest[M]; // whether an edge is on the shortest path int shortest_cnt; // number of vertices on the shortest path = # of edges + 1 voidfind_shortest(){ int i = 1; shortest_cnt = 1; while (i != n) { on_shortest[i] = shortest_cnt; shortest_cnt++; edge_on_shortest[pren[i]] = 1; edge_on_shortest[pren[i] ^ 1] = 1; auto [u, v, w] = edges[pren[i]]; i = u; } on_shortest[n] = shortest_cnt; // vertex index: 1, 2, ..., shortest_cnt // edge index: 1, 2, ...., shortest_cnt - 1 // [1] -(1)-> [2] -(2)-> [3] -> ... -> [cnt-1] -(cnt-1)-> [cnt] // ~~cochain complex!!!!~~ (no) }
int l[N]; int r[N]; voidfind_lr(int u, int lr[], int pre[]){ // find l or r. lr[] is l or r. pre is pre1 or pren. if (lr[u]) return; if (on_shortest[u]) lr[u] = u; else { auto [v, _, w] = edges[pre[u]]; find_lr(v, lr, pre); lr[u] = lr[v]; } }
vector<ll> add[N]; vector<ll> rmv[N]; multiset<ll> candidates; voidsolve(){ for (int i = 0; i < edges.size(); i++) { // enumerate all edges not on the shortest path if (edge_on_shortest[i]) continue; auto [u, v, w] = edges[i]; int l_index = on_shortest[l[u]]; int r_index = on_shortest[r[v]]; if (l_index >= r_index) continue; ll dist = dist1[u] + w + distn[v]; add[l_index].push_back(dist); rmv[r_index].push_back(dist); } ll ans = 0; int cnt = 0; rep(i, 1, shortest_cnt - 1) { for (ll u : add[i]) { candidates.insert(u); } for (ll u : rmv[i]) { candidates.erase(candidates.find(u)); } if (candidates.size()) { ll cur_f = *candidates.begin(); if (cur_f > ans) { ans = cur_f; cnt = 1; } elseif (cur_f == ans) { cnt++; } } }
if (ans == dist1[n]) cnt = m;
cout << ans << " " << cnt << endl; }
intmain(){ #ifdef D freopen("in", "r", stdin); #endif rin >> n >> m; rep(i, 1, m) { int s, t, c; rin >> s >> t >> c; g[s].push_back(make_tuple(t, c, edges.size())); edges.push_back(make_tuple(s, t, c)); g[t].push_back(make_tuple(s, c, edges.size())); edges.push_back(make_tuple(t, s, c)); // `edges` have both directions }