#nullable enable using System.Numerics; using T = System.Numerics.BigInteger; #region var (_input, _iter) = (Array.Empty(), 0); T I() where T : IParsable { while (_iter >= _input.Length) (_input, _iter) = (Console.ReadLine()!.Trim().Split(' '), 0); return T.Parse(_input[_iter++], null); } #endregion var n = I(); var m = I(); var ez = new (int, int)[n]; var wz = new Rational[n]; for (var i = 0; i < m; i++) { ez[i] = (I() - 1, I() - 1); wz[i] = new(I(), I()); } var g = new StaticGraph(ez, n, false).ToGraph(); var dz = g.Distances(0, wz, new(long.MaxValue)); var ans = new List(); for (var i = 1; i < n; i++) { var d = dz[i].Distance; ans.Add(d.P + " " + d.Q); } Console.WriteLine(string.Join(Environment.NewLine, ans)); readonly record struct Rational : IAdditiveIdentity, IAdditionOperators, ISubtractionOperators, IUnaryNegationOperators, IMultiplicativeIdentity, IMultiplyOperators, IDivisionOperators, IComparable, IEqualityOperators, IComparisonOperators { public T P { get; private init; } public T Q { get; private init; } public Rational(T p, T q) { if (q == T.Zero) { if (p != T.Zero) throw new DivideByZeroException(); (P, Q) = (0, 0); return; } if (q < T.Zero) (p, q) = (-p, -q); var (x, y) = (T.Abs(p), q); while (y > T.Zero) (x, y) = (y, x % y); (P, Q) = (p / x, q / x); } public Rational(T p) { (P, Q) = (p, T.One); } public static Rational AdditiveIdentity => new(T.Zero); public static Rational MultiplicativeIdentity => new(T.One); public static implicit operator Rational(T i) => new(i); public static Rational operator -(Rational r) => new(-r.P, r.Q); public static Rational operator +(Rational r1, Rational r2) => new(r1.P * r2.Q + r1.Q * r2.P, r1.Q * r2.Q); public static Rational operator -(Rational r1, Rational r2) => new(r1.P * r2.Q - r1.Q * r2.P, r1.Q * r2.Q); public static Rational operator *(Rational r1, Rational r2) => new(r1.P * r2.P, r1.Q * r2.Q); public static Rational operator /(Rational r1, Rational r2) => new(r1.P * r2.Q, r1.Q * r2.P); public static bool operator <(Rational r1, Rational r2) => r1.CompareTo(r2) < 0; public static bool operator <=(Rational r1, Rational r2) => r1.CompareTo(r2) <= 0; public static bool operator >(Rational r1, Rational r2) => r1.CompareTo(r2) > 0; public static bool operator >=(Rational r1, Rational r2) => r1.CompareTo(r2) >= 0; public int CompareTo(Rational r) => (P * r.Q).CompareTo(Q * r.P); } class StaticGraph { public int N { get; } public bool Directed { get; } public ReadOnlySpan<(int next, int edgeIndex)> Adjacencies(int of) => _adjacencies.AsSpan()[_starts[of].._starts[of + 1]]; public ReadOnlySpan<(int Ab, int Ad)> Edges => _edges; readonly (int Ab, int Ad)[] _edges; readonly (int, int)[] _adjacencies; readonly int[] _starts; public StaticGraph(IReadOnlyList<(int, int)> edges, int n, bool directed) { var ez = edges.ToArray(); var el = ez.Length; var m = directed ? el : (el << 1); var starts = new int[n + 1]; for (var i = 0; i < el; i++) { var (ab, ad) = ez[i]; starts[ab + 1]++; if (!directed) starts[ad + 1]++; } for (var i = 0; i < n; i++) starts[i + 1] += starts[i]; var adjacencies = new (int, int)[m]; var counts = starts.AsSpan().ToArray(); for (var i = 0; i < el; i++) { var (ab, ad) = ez[i]; adjacencies[counts[ab]++] = (ad, i); if (!directed) adjacencies[counts[ad]++] = (ab, i); } N = n; Directed = directed; _adjacencies = adjacencies; _edges = ez; _starts = starts; } } class Graph { public required StaticGraph StaticGraph { get; init; } } static class GraphBaseExtensions { public static Graph ToGraph(this StaticGraph g) => new(){ StaticGraph = g }; public static Span<(T Distance, int PrevV, int PrevE)> Distances( this Graph graph, int start, IReadOnlyList distances, T infinity ) where T : IComparable, IAdditiveIdentity, IAdditionOperators { var g = graph.StaticGraph; var res = new (T, int, int)[g.N].AsSpan(); for (var i = 0; i < res.Length; i++) res[i] = (infinity, -1, -1); var determined = new bool[g.N].AsSpan(); var q = new PriorityQueue(); q.Enqueue(start, res[start].Item1 = T.AdditiveIdentity); while (q.Count > 0) { var v = q.Dequeue(); if (determined[v]) continue; determined[v] = true; var cd = res[v].Item1; var adjacencies = g.Adjacencies(v); foreach (var (next, ei) in adjacencies) { var d = cd + distances[ei]; if (res[next].Item1.CompareTo(d) <= 0) continue; res[next] = (d, v, ei); q.Enqueue(next, d); } } return res; } }