#include using namespace std; #include namespace mp = boost::multiprecision; using Bint = mp::cpp_int; //約分を毎回しない template struct yuri { T num, den; yuri() : num(0), den(1) {} yuri(T a) : num(a), den(1) {} yuri(int a) : num(a), den(1) {} yuri(long long a) : num(a), den(1) {} yuri(T a, T b) : num(a), den(b) {} void safe(){ if(num < 0) den *= -1, num *= -1; T v = gcd(num, den); num /= v, den /= v; } yuri& operator++() { num += den; return *this; } yuri& operator--() { num -= den; return *this; } yuri& operator+=(const yuri& rhs) { num *= rhs.den; num += rhs.num * den; den *= rhs.den; return *this; } yuri& operator-=(const yuri& rhs) { num *= rhs.den; num -= rhs.num * den; den *= rhs.den; return *this; } yuri& operator*=(const yuri& rhs) { num *= rhs.num; den *= rhs.den; return *this; } yuri& operator/=(const yuri& rhs) { num *= rhs.den; den *= rhs.num; return *this ; } yuri operator+() const { return *this; } yuri operator-() const { return yuri() - *this; } friend yuri operator+(const yuri lhs, const yuri rhs) { return yuri(lhs) += rhs; } friend yuri operator-(const yuri& lhs, const yuri& rhs) { return yuri(lhs) -= rhs; } friend yuri operator*(const yuri& lhs, const yuri& rhs) { return yuri(lhs) *= rhs; } friend yuri operator/(const yuri& lhs, const yuri& rhs) { return yuri(lhs) /= rhs; } friend bool operator==(const yuri& lhs, const yuri& rhs) { return (lhs.num * rhs.den == rhs.num * lhs.den); } friend bool operator!=(const yuri& lhs, const yuri& rhs) { return (lhs.num * rhs.den != rhs.num * lhs.den); } friend bool operator<(const yuri& lhs, const yuri& rhs) { return (lhs.num*rhs.den(const yuri& lhs, const yuri& rhs) { return (lhs.num*rhs.den>lhs.den*rhs.num); } friend bool operator>=(const yuri& lhs, const yuri& rhs) { return (lhs.num*rhs.den>=lhs.den*rhs.num); } friend ostream& operator << (ostream &os, const yuri rhs) noexcept { return os << rhs.num << ' ' << rhs.den; } }; template struct csr { struct Node { csr* g; int u; template void emplace_back(Args&&... args){ g->add_edge(u, T(std::forward(args)...)); } auto begin(){ return g->E.begin() + g->start[u]; } auto end(){ return g->E.begin() + g->start[u + 1]; } int size(){ return g->start[u + 1] - g->start[u]; } T& operator[](int p){ return *(begin() + p); } }; int N; std::vector start; std::vector E; std::vector> edge; csr(int n) : N(n), start(n + 1) {edge.reserve(n);} void add_edge(int u, T v){ assert(0 <= u && u < N); start[u + 1]++; edge.emplace_back(u, v); } void build(){ E.resize(edge.size()); for(int i = 0; i < N; i++) start[i + 1] += start[i]; auto cnt = start; for(auto [u, v] : edge) E[cnt[u]++] = v; } const int size() {return N;} Node operator[](int u) {return Node{this, u};} }; int main(){ ios::sync_with_stdio(false); cin.tie(0); int n, m; cin >> n >> m; csr>> g(n); int u, v, a, b; for(int i = 0; i < m; i++){ cin >> u >> v >> a >> b; u--, v--; g[u].emplace_back(v, yuri(a, b)); g[v].emplace_back(u, yuri(a, b)); } g.build(); vector> dp(n, yuri(1 << 30, 1)); priority_queue,int>, vector,int>>, greater,int>>> pq; dp[0] = yuri(0, 1); pq.push({dp[0], 0}); while(!pq.empty()){ auto [d, v] = pq.top(); pq.pop(); if(d > dp[v]) continue; for(auto [u, w] : g[v]){ auto L = d + w; if(L >= dp[u]) continue; dp[u] = L; pq.emplace(dp[u], u); } } for(int v = 1; v < n; v++){ dp[v].safe(); cout << dp[v] << '\n'; } }