Problem:
Score : 400 points

Problem Statement

Kenkoooo is planning a trip in Republic of Snuke.
In this country, there are n cities and m trains running.
The cities are numbered 1 through n, and the i-th train connects City u_i and v_i bidirectionally.
Any city can be reached from any city by changing trains.

Two currencies are used in the country: yen and snuuk.
Any train fare can be paid by both yen and snuuk.
The fare of the i-th train is a_i yen if paid in yen, and b_i snuuk if paid in snuuk.

In a city with a money exchange office, you can change 1 yen into 1 snuuk.
However, when you do a money exchange, you have to change all your yen into snuuk.
That is, if Kenkoooo does a money exchange when he has X yen, he will then have X snuuk.
Currently, there is a money exchange office in every city, but the office in City i will shut down in i years and can never be used in and after that year.

Kenkoooo is planning to depart City s with 10^{15} yen in his pocket and head for City t, and change his yen into snuuk in some city while traveling.
It is acceptable to do the exchange in City s or City t.

Kenkoooo would like to have as much snuuk as possible when he reaches City t by making the optimal choices for the route to travel and the city to do the exchange.
For each i=0,...,n-1, find the maximum amount of snuuk that Kenkoooo has when he reaches City t if he goes on a trip from City s to City t after i years.
You can assume that the trip finishes within the year.

Constraints

2 \leq n \leq 10^5

1 \leq m \leq 10^5

1 \leq s,t \leq n

s \neq t

1 \leq u_i < v_i \leq n

1 \leq a_i,b_i \leq 10^9

If i\neq j, then u_i \neq u_j or v_i \neq v_j.

Any city can be reached from any city by changing trains.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

n m s t
u_1 v_1 a_1 b_1
:
u_m v_m a_m b_m

Output

Print n lines.
In the i-th line, print the maximum amount of snuuk that Kenkoooo has when he reaches City t if he goes on a trip from City s to City t after i-1 years.

Sample Input 1

4 3 2 3
1 4 1 100
1 2 1 10
1 3 20 1

Sample Output 1

999999999999998
999999999999989
999999999999979
999999999999897

After 0 years, it is optimal to do the exchange in City 1.

After 1 years, it is optimal to do the exchange in City 2.

Note that City 1 can still be visited even after the exchange office is closed.
Also note that, if it was allowed to keep 1 yen when do the exchange in City 2 and change the remaining yen into snuuk, we could reach City 3 with 999999999999998 snuuk, but this is NOT allowed.

After 2 years, it is optimal to do the exchange in City 3.

After 3 years, it is optimal to do the exchange in City 4.
Note that the same train can be used multiple times.

Sample Input 2

8 12 3 8
2 8 685087149 857180777
6 7 298270585 209942236
2 4 346080035 234079976
2 5 131857300 22507157
4 8 30723332 173476334
2 6 480845267 448565596
1 4 181424400 548830121
4 5 57429995 195056405
7 8 160277628 479932440
1 6 475692952 203530153
3 5 336869679 160714712
2 7 389775999 199123879

Sample Output 2

999999574976994
999999574976994
999999574976994
999999574976994
999999574976994
999999574976994
999999574976994
999999574976994

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using Atcoder;
using Atcoder.Graph;
class P
{
    static void Main()
    {
        int n, m, s, t;
        n = Std.ReadInt();
        m = Std.ReadInt();
        s = Std.ReadInt() - 1;
        t = Std.ReadInt() - 1;
        Graph gy = new Graph(n);
        Graph gs = new Graph(n);
        for (int i = 0; i < m; i++)
        {
            int u, v, a, b;
            u = Std.ReadInt() - 1;
            v = Std.ReadInt() - 1;
            a = Std.ReadInt();
            b = Std.ReadInt();
            gy.SetUEdge(u, v, a);
            gs.SetUEdge(u, v, b);
        }
        long[] yen = gy.Dijkstra(s);
        long[] snu = gs.Dijkstra(t);
        long[] cost = new long[n];
        for (int i = 0; i < n; i++)
            cost[i] = yen[i] + snu[i];
        long[] ans_cost = new long[n];
        ans_cost[n - 1] = cost[n - 1];
        for (int i = n - 2; i >= 0; i--)
            ans_cost[i] = Math.Min(ans_cost[i + 1], cost[i]);
        foreach (var i in ans_cost)
            Std.WriteLine(1000000000000000 - i);
    }
}
/*--------------------------------------------------------------------*/
namespace Atcoder
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    //標準入出力
    static class Std
    {
        [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
        private static extern int scanf(string format, out char c);
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を無視したの次の1文字を読み取ります。
        /// </summary>
        public static char ReadChar()
        {
            char c;
            do
            {
                scanf("%c", out c);
            } while (c == ' ' || c == '\n');
            return c;
        }
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を区切りとした次の文字列を読み取ります。
        /// </summary>
        public static string ReadString()
        {
            StringBuilder sb = new StringBuilder();
            char c = ReadChar();
            while (c != ' ' && c != '\n')
            {
                sb.Append(c);
                scanf("%c", out c);
            }
            return sb.ToString();
        }
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を区切りとした次の文字列を、それと等価な符号付き64ビット整数として読み取ります。
        /// </summary>
        public static long ReadLong()
        {
            string s = ReadString();
            try
            {
                return checked(long.Parse(s));
            }
            catch { throw; }
        }
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を区切りとした次の文字列を、それと等価な符号付き32ビット整数として読み取ります。
        /// </summary>
        public static int ReadInt()
        {
            try
            {
                return checked((int)ReadLong());
            }
            catch { throw; }
        }
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を区切りとした次の文字列を、それと等価な倍精度浮動小数点数として読み取ります。
        /// </summary>
        public static double ReadDouble()
        {
            try
            {
                string s = ReadString();
                return double.Parse(s);
            }
            catch { throw; }
        }
        /// <summary>
        /// 標準入力ストリームから半角スペースと改行を区切りとした次の文字列を、それと等価な10進数として読み取ります。
        /// </summary>
        public static decimal ReadDecimal()
        {
            try
            {
                string s = ReadString();
                return decimal.Parse(s);
            }
            catch { throw; }
        }
        [System.Runtime.InteropServices.DllImport("msvcrt.dll")]
        private static extern void printf(string s);
        /// <summary>
        /// 現在の行終端記号を標準出力ストリームに書き込みます。
        /// </summary>
        public static void WriteLine()
        {
            printf("\n");
        }
        /// <summary>
        /// 指定した文字列値を標準出力ストリームに書き込み、続けて現在の行終端記号を書き込みます。
        /// </summary>
        public static void WriteLine(string value)
        {
            printf(value);
            WriteLine();
        }
        /// <summary>
        /// 指定したオブジェクトのテキスト表現を標準出力ストリームに書き込み、続けて現在の行終端記号を書き込みます。
        /// </summary>
        public static void WriteLine(object value)
        {
            try
            {
                printf(value.ToString());
                WriteLine();
            }
            catch { throw; }
        }
        /// <summary>
        /// 指定した書式情報を使用して、指定したオブジェクト配列のテキスト表現を標準出力ストリームに書き込み、続けて行終端記号を書き込みます。
        /// </summary>
        public static void WriteLine(string format, params object[] values)
        {
            try
            {
                WriteLine(String.Format(format, values));
            }
            catch { throw; }
        }
        /// <summary>
        /// 指定した文字列値を標準出力ストリームに書き込みます。
        /// </summary>
        public static void Write(string value)
        {
            printf(value);
        }
        /// <summary>
        /// 指定したオブジェクトのテキスト表現を標準出力ストリームに書き込みます。
        /// </summary>
        public static void Write(object value)
        {
            try
            {
                Write(value.ToString());
            }
            catch { throw; }
        }
        /// <summary>
        /// 指定した書式情報を使用して、指定したオブジェクト配列のテキスト表現を標準出力ストリームに書き込みます。
        /// </summary>
        public static void Write(string format, params object[] values)
        {
            try
            {
                Write(String.Format(format, values));
            }
            catch { throw; }
        }
    }
    //整数値のペア
    class Pair : IComparer<Pair>
    {
        public long x;
        public long y;
        public Pair(long x, long y)
        {
            this.x = x;
            this.y = y;
        }
        int IComparer<Pair>.Compare(Pair p, Pair q)
        {
            int n = (p.x > q.x) ? 1 : (p.x < q.x) ? -1 : (p.y > q.y) ? 1 : (p.y < q.y) ? -1 : 0;
            return n;
        }
    }
    namespace PriorityQueue //優先度付きキュー
    {
        using System.Collections.Generic;
        //優先度付きキュー
        class PriorityQueue<T>
        {
            private readonly List<T> heap;
            private readonly Comparison<T> compare;
            private int size;
            public PriorityQueue() : this(Comparer<T>.Default) { }
            public PriorityQueue(IComparer<T> comparer) : this(16, comparer.Compare) { }
            public PriorityQueue(Comparison<T> comparison) : this(16, comparison) { }
            public PriorityQueue(int capacity, Comparison<T> comparison)
            {
                this.heap = new List<T>(capacity);
                this.compare = comparison;
            }
            /// <summary>
            /// 優先度付きキューに要素を追加します。時間計算量はO(log(size))です。
            /// </summary>
            public void Enqueue(T item)
            {
                this.heap.Add(item);
                var i = size++;
                while (i > 0)
                {
                    var p = (i - 1) >> 1;
                    if (compare(this.heap[p], item) <= 0)
                        break;
                    this.heap[i] = heap[p];
                    i = p;
                }
                this.heap[i] = item;
            }
            /// <summary>
            /// 優先度付きキューから先頭の要素を取り出し返します。取り出した要素は削除されます。
            /// </summary>
            public T Dequeue()
            {
                var ret = this.heap[0];
                var x = this.heap[--size];
                var i = 0;
                while ((i << 1) + 1 < size)
                {
                    var a = (i << 1) + 1;
                    var b = (i << 1) + 2;
                    if (b < size && compare(heap[b], heap[a]) < 0) a = b;
                    if (compare(heap[a], x) >= 0)
                        break;
                    heap[i] = heap[a];
                    i = a;
                }
                heap[i] = x;
                heap.RemoveAt(size);
                return ret;
            }
            private bool binary_search(T x, int imin, int imax)
            {
                if (imax < imin)
                    return false;
                int imid = imin + (imax - imin) / 2;
                if (compare(heap[imid], x) > 0)
                    return binary_search(x, imin, imid - 1);
                else if (compare(heap[imid], x) < 0)
                    return binary_search(x, imid + 1, imax);
                return true;
            }
            /// <summary>
            /// 優先度付きキューに同じ要素が存在するか調べます。時間計算量はO(log(size))です。
            /// </summary>
            public bool Contains(T x)
            {
                return binary_search(x, 0, heap.Count - 1);
            }
            /// <summary>
            /// 優先度付きキューの先頭の要素を返します。
            /// </summary>
            public T Peek() { return heap[0]; }
            /// <summary>
            /// 優先度付きキューの要素数を返します。
            /// </summary>
            public int Count { get { return size; } }
            /// <summary>
            /// 優先度付きキューに要素が入っているかどうか調べます。
            /// </summary>
            public bool Any() { return size > 0; }
        }
    }
    namespace Graph //グラフ
    {
        using System.Collections.Generic;
        using Atcoder.PriorityQueue;
        class Node
        {
            public int id;
            public List<Edge> edges = new List<Edge>();
            public Node(int id)
            {
                this.id = id;
            }
        }
        class Edge
        {
            public int g;
            public long l = 1;
            public Edge(int g)
            {
                this.g = g;
            }
            public Edge(int g, long l)
            {
                this.g = g;
                this.l = l;
            }
        }
        class Graph
        {
            public Node[] nodes;
            public Graph(int n)
            {
                nodes = new Node[n];
                for (int i = 0; i < n; i++) nodes[i] = new Node(i);
            }
            /// <summary>
            /// 指定した2つの値に対応した頂点の間に向きのない辺を張ります。
            /// </summary>
            public void SetUEdge(int s, int g)
            {
                nodes[s].edges.Add(new Edge(g));
                nodes[g].edges.Add(new Edge(s));
            }
            /// <summary>
            /// 指定した2つの値に対応した頂点の間に、指定した長さの向きのない辺を張ります。
            /// </summary>
            public void SetUEdge(int s, int g, long l)
            {
                nodes[s].edges.Add(new Edge(g, l));
                nodes[g].edges.Add(new Edge(s, l));
            }
            /// <summary>
            /// 指定した2つの値に対応した頂点の間に方向付きの辺を張ります。
            /// </summary>
            public void SetEdge(int s, int g)
            {
                nodes[s].edges.Add(new Edge(g));
            }
            /// <summary>
            /// 指定した2つの値に対応した頂点の間に、指定した長さの方向付きの辺を張ります。
            /// </summary>
            public void SetEdge(int s, int g, long l)
            {
                nodes[s].edges.Add(new Edge(g, l));
            }
            /// <summary>
            /// 指定した頂点から各頂点までの最短距離を格納した配列を返します。
            /// </summary>
            public long[] Dijkstra(int s)
            {
                int n = nodes.Length;
                Pair[] d = new Pair[n];
                for (int i = 0; i < n; i++) d[i] = new Pair(i, long.MaxValue);
                PriorityQueue<Pair> Q = new PriorityQueue<Pair>(d[0]);
                d[s].y = 0;
                Q.Enqueue(d[s]);
                while (Q.Any())
                {
                    var u = Q.Dequeue();
                    for (int i = 0; i < nodes[u.x].edges.Count; i++)
                    {
                        var alt = u.y + nodes[u.x].edges[i].l;
                        var v = nodes[u.x].edges[i].g;
                        if (d[v].y > alt)
                        {
                            d[v].y = alt;
                            Q.Enqueue(d[v]);
                        }
                    }
                }
                long[] r = new long[n];
                for (int i = 0; i < n; i++)
                    r[i] = d[i].y;
                return r;
            }
        }
    }
}