Problem:
Score : 600 points

Problem Statement

There is a tree with N vertices numbered 1 to N.
The i-th edge in this tree connects Vertex a_i and Vertex b_i, and the color and length of that edge are c_i and d_i, respectively.
Here the color of each edge is represented by an integer between 1 and N-1 (inclusive). The same integer corresponds to the same color, and different integers correspond to different colors.

Answer the following Q queries:

Query j (1 \leq j \leq Q): assuming that the length of every edge whose color is x_j is changed to y_j, find the distance between Vertex u_j and Vertex v_j. (The changes of the lengths of edges do not affect the subsequent queries.)

Constraints

2 \leq N \leq 10^5

1 \leq Q \leq 10^5

1 \leq a_i, b_i \leq N

1 \leq c_i \leq N-1

1 \leq d_i \leq 10^4

1 \leq x_j \leq N-1

1 \leq y_j \leq 10^4

1 \leq u_j < v_j \leq N

The given graph is a tree.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N Q
a_1 b_1 c_1 d_1
:
a_{N-1} b_{N-1} c_{N-1} d_{N-1}
x_1 y_1 u_1 v_1
:
x_Q y_Q u_Q v_Q

Output

Print Q lines. The j-th line (1 \leq j \leq Q) should contain the answer to Query j.

Sample Input 1

5 3
1 2 1 10
1 3 2 20
2 4 4 30
5 2 1 40
1 100 1 4
1 100 1 5
3 1000 3 4

Sample Output 1

130
200
60

The graph in this input is as follows:

Here the edges of Color 1 are shown as solid red lines, the edge of Color 2 is shown as a bold green line, and the edge of Color 4 is shown as a blue dashed line.

Query 1: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 4 is 100 + 30 = 130.

Query 2: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 5 is 100 + 100 = 200.

Query 3: Assuming that the length of every edge whose color is 3 is changed to 1000 (there is no such edge), the distance between Vertex 3 and Vertex 4 is 20 + 10 + 30 = 60. Note that the edges of Color 1 now have their original lengths.

Solution in C# (Mono-csc 3.5.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Numerics;
using System.Threading;
using static System.Math;
using static System.Array;
using static AtCoder.IO_ShortCut;
using static AtCoder.Tool;
using static AtCoder.ModInt;
namespace AtCoder
{
    class AC
    {
        const int MOD = 1000000007;
        //const int MOD = 998244353;

        const int INF = int.MaxValue / 2;
        const long SINF = long.MaxValue / 2;
        const double EPS = 1e-8;
        static readonly int[] dI = { 0, 1, 0, -1, 1, -1, -1, 1 };
        static readonly int[] dJ = { 1, 0, -1, 0, 1, 1, -1, -1 };
        //static List<List<int>> G = new List<List<int>>();
        //static List<List<Edge>> G = new List<List<Edge>>();
        //static List<Edge> E = new List<Edge>();
        static void Main(string[] args)
        {
            var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(sw);

            var th = new Thread(Run, 1 << 26);
            th.Start();
            th.Join();

            //Run();
            Console.Out.Flush();
        }

        static void Run()
        {
            int Testcase = 1;
            for (var _ = 0; _ < Testcase; _++) Solve();
        }
        static void Solve()
        {
            int N, Q;
            Input(out N, out Q);
            var G = new List<List<Edge>>();
            for (var i = 0; i < N; i++) G.Add(new List<Edge>());
            for(var i = 0; i < N - 1; i++)
            {
                int a, b, c;
                long d;
                Input(out a, out b, out c, out d);
                a--;b--;c--;
                G[a].Add(new Edge(b, c, d));
                G[b].Add(new Edge(a, c, d));
            }
            //LCA
            var par = new int[30, N];
            var dist = new int[N];
            par[0, 0] = -1;
            dist[0] = 0;
            var dfs = new Stack<(int, int)>();
            dfs.Push((0, -1));
            while (dfs.Any())
            {
                var t = dfs.Pop();
                var v = t.Item1;
                var pre = t.Item2;
                foreach (var ed in G[v])
                {
                    var nx = ed.to;
                    if (nx == pre) continue;
                    par[0, nx] = v;
                    dist[nx] = dist[v] + 1;
                    dfs.Push((nx, v));
                }
            }
            for (var i = 1; i < 30; i++)
            {
                for (var j = 0; j < N; j++)
                {
                    if (par[i - 1, j] == -1) par[i, j] = -1;
                    else par[i, j] = par[i - 1, par[i - 1, j]];
                }
            }
            int LCA(int u, int v)
            {
                if (dist[u] < dist[v])
                {
                    var kep = u;
                    u = v;
                    v = kep;
                }
                for (var i = 0; i < 30; i++)
                {
                    if (Bit(dist[u] - dist[v], i))
                    {
                        u = par[i, u];
                    }
                }
                if (u == v) return u;
                for (var i = 29; i >= 0; i--)
                {
                    if (par[i, u] != par[i, v])
                    {
                        u = par[i, u];
                        v = par[i, v];
                    }
                }
                return par[0, u];
            }



            var Qr = new List<List<int>>();
            for (var i = 0; i < N; i++) Qr.Add(new List<int>());
            var num = new long[N];
            var sum = new long[N];
            var ans = new long[Q];
            var x = new int[Q];
            var y = new long[Q];
            for(var i = 0; i < Q; i++)
            {
                int u, v;
                Input(out x[i], out y[i], out u, out v);
                x[i]--;u--;v--;
                Qr[u].Add(i + 1);
                Qr[v].Add(i + 1);
                Qr[LCA(u, v)].Add(-(i + 1));
            }
            /*for(var i = 0; i < N; i++)
            {
                OutL($"{i}::");
                Out_Sep(Qr[i]);
            }*/


            long dsum = 0;
            void dfs2(int v, int pre)
            {
                /*OutL($"now={v}");
                Out_Sep(num);
                Out_Sep(sum);*/
                foreach(var z in Qr[v])
                {
                    //OutL($"z={z},Query={Abs(z) - 1}");
                    int ind = Abs(z) - 1;
                    long now = dsum - sum[x[ind]] + num[x[ind]] * y[ind];

                    if (z > 0) ans[ind] += now;
                    else ans[ind] -= 2 * now;
                }

                foreach(var ed in G[v])
                {
                    int nx = ed.to;
                    if (nx == pre) continue;
                    int col = ed.color;
                    long D = ed.dist;

                    dsum += D;
                    num[col]++;
                    sum[col] += D;
                    dfs2(nx, v);

                    dsum -= D;
                    num[col]--;
                    sum[col] -= D;
                }
            }
            dfs2(0, -1);
            Out_Sep(ans, "\n");

        }
        public struct Edge
        {
            public int from;

            public int to;
            public long dist;

            public int color;

            public Edge(int t, long c)
            {
                from = -1;
                to = t;
                dist = c;

                color = -1;
            }
            /*public Edge(int f, int t, long c)
            {
                from = f;
                to = t;
                dist = c;

                color = -1;
            }*/

            public Edge(int t, int c, long d)
            {
                from = -1;
                to = t;
                color = c;
                dist = d;
            }
        }
    }
    struct ModInt
    {
        public long value;
        private const int MOD = 1000000007;
        //private const int MOD = 998244353;
        public ModInt(long value) { this.value = value; }
        public static implicit operator ModInt(long a)
        {
            var ret = a % MOD;
            return new ModInt(ret < 0 ? (ret + MOD) : ret);
        }
        public static ModInt operator +(ModInt a, ModInt b) => (a.value + b.value);
        public static ModInt operator -(ModInt a, ModInt b) => (a.value - b.value);
        public static ModInt operator *(ModInt a, ModInt b) => (a.value * b.value);
        public static ModInt operator /(ModInt a, ModInt b) => a * Modpow(b, MOD - 2);
        public static ModInt operator <<(ModInt a, int n) => (a.value << n);
        public static ModInt operator >>(ModInt a, int n) => (a.value >> n);
        public static ModInt operator ++(ModInt a) => a.value + 1;
        public static ModInt operator --(ModInt a) => a.value - 1;
        public static ModInt Modpow(ModInt a, long n)
        {
            var k = a;
            ModInt ret = 1;
            while (n > 0)
            {
                if ((n & 1) != 0) ret *= k;
                k *= k;
                n >>= 1;
            }
            return ret;
        }
        private static readonly List<long> Factorials = new List<long>() { 1 };
        public static ModInt Fac(long n)
        {
            for (var i = Factorials.Count(); i <= n; i++)
            {
                Factorials.Add((Factorials[i - 1] * i) % MOD);
            }
            return Factorials[(int)n];
        }
        public static ModInt nCr(long n, long r)
        {
            return n < r ? 0 : Fac(n) / (Fac(r) * Fac(n - r));
        }
        public static explicit operator int(ModInt a) => (int)a.value;
    }
    static class IO_ShortCut
    {
        public static string[] _ReadSplit => Console.ReadLine().Split();
        public static int[] _ReadSplitInt => ConvertAll(Console.ReadLine().Split(), int.Parse);
        public static long[] _ReadSplitLong => ConvertAll(Console.ReadLine().Split(), long.Parse);
        public static double[] _ReadSplit_Double => ConvertAll(Console.ReadLine().Split(), double.Parse);
        public static string Str => Console.ReadLine();
        public static int Int => int.Parse(Console.ReadLine());
        public static long Long => long.Parse(Console.ReadLine());
        public static double Double => double.Parse(Console.ReadLine());
        public static T Conv<T>(string input)
        {
            if (typeof(T).Equals(typeof(ModInt)))
            {
                return (T)(dynamic)(long.Parse(input));
            }
            return (T)Convert.ChangeType(input, typeof(T));
        }
        public static void Input<T>(out T a) => a = Conv<T>(Console.ReadLine());
        public static void Input<T, U>(out T a, out U b)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); }
        public static void Input<T, U, V>(out T a, out U b, out V c)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); }
        public static void Input<T, U, V, W>(out T a, out U b, out V c, out W d)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); }
        public static void Input<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
        { var q = _ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); e = Conv<X>(q[4]); }

        public static void OutL(object s) => Console.WriteLine(s);
        public static void Out_Sep<T>(IEnumerable<T> s) => Console.WriteLine(string.Join(" ", s));
        public static void Out_Sep<T>(IEnumerable<T> s, string sep) => Console.WriteLine(string.Join($"{sep}", s));
        public static void Out_Sep(params object[] s) => Console.WriteLine(string.Join(" ", s));
        public static void Out_One(object s) => Console.Write($"{s} ");
        public static void Out_One(object s, string sep) => Console.Write($"{s}{sep}");
        public static void Endl() => Console.WriteLine();
    }
    public static class Tool
    {
        static public void Initialize<T>(ref T[] array, T initialvalue)
        {
            array = ConvertAll(array, x => initialvalue);
        }
        static public void Swap<T>(ref T a, ref T b)
        {
            T keep = a;
            a = b;
            b = keep;
        }
        static public void Display<T>(T[,] array2d, int n, int m)
        {
            for (var i = 0; i < n; i++)
            {
                for (var j = 0; j < m; j++)
                {
                    Console.Write($"{array2d[i, j]} ");
                }
                Console.WriteLine();
            }
        }
        static public long Gcd(long a, long b)
        {
            if (a == 0 || b == 0) return Max(a, b);
            return a % b == 0 ? b : Gcd(b, a % b);
        }
        static public long LPow(int a, int b) => (long)Pow(a, b);
        static public bool Bit(long x, int dig) => ((1L << dig) & x) != 0;
        static public int Sig(long a) => a == 0 ? 0 : (int)(a / Abs(a));
    }
}