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 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.IO;
using System.Text;
using System.Diagnostics;

using static util;
using P = pair<int, int>;

using Binary = System.Func<System.Linq.Expressions.ParameterExpression,
                           System.Linq.Expressions.ParameterExpression,
                           System.Linq.Expressions.BinaryExpression>;
using Unary = System.Func<System.Linq.Expressions.ParameterExpression,
                          System.Linq.Expressions.UnaryExpression>;

class Program {
    static StreamWriter sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
    static Scan sc = new Scan();
    const int M = 1000000007;
    const int M2 = 998244353;
    const long LM = 1L << 60;
    const double eps = 1e-11;
    static void Main(string[] args)
    {
        int n, q;
        sc.Multi(out n, out q);
        edge = new List<pair<int, P>>[n];
        var edge2 = new List<pair<long, int>>[n];
        needcol = new Dictionary<int, P>[n];
        var cols = new P[n];
        for (int i = 0; i < n; i++)
        {
            edge[i] =  new List<pair<int, P>>();
            edge2[i] =  new List<pair<long, int>>();
            needcol[i] = new Dictionary<int, P>();
            cols[i] = new P(0, 0);
        }
        for (int i = 0; i < n - 1; i++)
        {
            int u, v, c, d;
            sc.Multi(out u, out v, out c, out d);
            --u;
            --v;
            --c;
            edge[u].Add(new pair<int, P>(v, new P(c, d)));
            edge[v].Add(new pair<int, P>(u, new P(c, d)));
            edge2[u].Add(new pair<long, int>(d, v));
            edge2[v].Add(new pair<long, int>(d, u));
        }
        var lca = new LCATree(n, edge2);
        var que = new int[q][];
        for (int i = 0; i < q; i++)
        {
            que[i] = sc.IntArr;
            --que[i][0];
            --que[i][2];
            --que[i][3];
            int p = lca.getLCA(que[i][2], que[i][3]);
            if (!needcol[que[i][2]].ContainsKey(que[i][0]))
                needcol[que[i][2]].Add(que[i][0], new P(0, 0));
            if (!needcol[que[i][3]].ContainsKey(que[i][0]))
                needcol[que[i][3]].Add(que[i][0], new P(0, 0));
            if (!needcol[p].ContainsKey(que[i][0]))
                needcol[p].Add(que[i][0], new P(0, 0));
        }
        dfs(0, -1, cols);
        foreach (var item in que)
        {
            long d = lca.dist(item[2], item[3]);
            int p = lca.getLCA(item[2], item[3]);
            int cnt = needcol[item[2]][item[0]].v1 + needcol[item[3]][item[0]].v1 - needcol[p][item[0]].v1 * 2;
            int len = needcol[item[2]][item[0]].v2 + needcol[item[3]][item[0]].v2 - needcol[p][item[0]].v2 * 2;
            Prt(d - len + cnt * item[1]);
        }
        sw.Flush();
    }
    static List<pair<int, P>>[] edge;
    static Dictionary<int, P>[] needcol;
    static void dfs(int p, int par, P[] cols) {
        var dic = new Dictionary<int, P>();
        foreach (var item in needcol[p])
        {
            dic.Add(item.Key, new P(cols[item.Key].v1, cols[item.Key].v2));
        }
        needcol[p] = dic;
        foreach (var item in edge[p])
        {
            if (item.v1 == par) continue;
            ++cols[item.v2.v1].v1;
            cols[item.v2.v1].v2 += item.v2.v2;
            dfs(item.v1, p, cols);
            --cols[item.v2.v1].v1;
            cols[item.v2.v1].v2 -= item.v2.v2;
        }
    }

    static void DBG(string a) => Console.WriteLine(a);
    static void DBG<T>(IEnumerable<T> a) => DBG(string.Join(" ", a));
    static void DBG(params object[] a) => DBG(string.Join(" ", a));
    static void Prt(string a) => sw.WriteLine(a);
    static void Prt<T>(IEnumerable<T> a) => Prt(string.Join(" ", a));
    static void Prt(params object[] a) => Prt(string.Join(" ", a));
}
class pair<T, U> : IComparable<pair<T, U>> {
    public T v1;
    public U v2;
    public pair() : this(default(T), default(U)) {}
    public pair(T v1, U v2) { this.v1 = v1; this.v2 = v2; }
    public int CompareTo(pair<T, U> a) {
        int c = Comparer<T>.Default.Compare(v1, a.v1);
        return c != 0 ? c : Comparer<U>.Default.Compare(v2, a.v2);
    }
    public override string ToString() => v1 + " " + v2;
    public void Deconstruct(out T a, out U b) { a = v1; b = v2; }
    public static bool operator>(pair<T, U> a, pair<T, U> b) => a.CompareTo(b) > 0;
    public static bool operator<(pair<T, U> a, pair<T, U> b) => a.CompareTo(b) < 0;
    public static bool operator>=(pair<T, U> a, pair<T, U> b) => a.CompareTo(b) >= 0;
    public static bool operator<=(pair<T, U> a, pair<T, U> b) => a.CompareTo(b) <= 0;
}
static class util {
    public static pair<T, U> make_pair<T, U>(T v1, U v2) => new pair<T, U>(v1, v2);
    public static T sq<T>(T a) => Operator<T>.Multiply(a, a);
    public static T Max<T>(params T[] a) => a.Max();
    public static T Min<T>(params T[] a) => a.Min();
    public static bool inside(int i, int j, int h, int w) => i >= 0 && i < h && j >= 0 && j < w;
    static readonly int[] dd = { 0, 1, 0, -1 };
    static readonly string dstring = "RDLU";
    public static P[] adjacents(this P p) => adjacents(p.v1, p.v2);
    public static P[] adjacents(this P p, int h, int w) => adjacents(p.v1, p.v2, h, w);
    public static pair<P, char>[] adjacents_with_str(int i, int j)
        => Enumerable.Range(0, dd.Length).Select(k => new pair<P, char>(new P(i + dd[k], j + dd[k ^ 1]), dstring[k])).ToArray();
    public static pair<P, char>[] adjacents_with_str(int i, int j, int h, int w)
        => Enumerable.Range(0, dd.Length).Select(k => new pair<P, char>(new P(i + dd[k], j + dd[k ^ 1]), dstring[k])).Where(p => inside(p.v1.v1, p.v1.v2, h, w)).ToArray();
    public static P[] adjacents(int i, int j)
        => Enumerable.Range(0, dd.Length).Select(k => new P(i + dd[k], j + dd[k ^ 1])).ToArray();
    public static P[] adjacents(int i, int j, int h, int w)
        => Enumerable.Range(0, dd.Length).Select(k => new P(i + dd[k], j + dd[k ^ 1])).Where(p => inside(p.v1, p.v2, h, w)).ToArray();
    public static void Assert(bool cond) { if (!cond) throw new Exception(); }
    public static Dictionary<T, int> compress<T>(this IEnumerable<T> a)
        => a.Distinct().OrderBy(v => v).Select((v, i) => new { v, i }).ToDictionary(p => p.v, p => p.i);
    public static Dictionary<T, int> compress<T>(params IEnumerable<T>[] a) => compress(a.Aggregate(Enumerable.Union));
    public static void swap<T>(ref T a, ref T b) where T : struct { var t = a; a = b; b = t; }
    public static void swap<T>(this IList<T> a, int i, int j) where T : struct { var t = a[i]; a[i] = a[j]; a[j] = t; }
    public static T[] copy<T>(this IList<T> a) {
        var ret = new T[a.Count];
        for (int i = 0; i < a.Count; i++) ret[i] = a[i];
        return ret;
    }
}
static class Operator<T> {
    static readonly ParameterExpression x = Expression.Parameter(typeof(T), "x");
    static readonly ParameterExpression y = Expression.Parameter(typeof(T), "y");
    public static readonly Func<T, T, T> Add = Lambda(Expression.Add);
    public static readonly Func<T, T, T> Subtract = Lambda(Expression.Subtract);
    public static readonly Func<T, T, T> Multiply = Lambda(Expression.Multiply);
    public static readonly Func<T, T, T> Divide = Lambda(Expression.Divide);
    public static readonly Func<T, T> Plus = Lambda(Expression.UnaryPlus);
    public static readonly Func<T, T> Negate = Lambda(Expression.Negate);
    public static Func<T, T, T> Lambda(Binary op) => Expression.Lambda<Func<T, T, T>>(op(x, y), x, y).Compile();
    public static Func<T, T> Lambda(Unary op) => Expression.Lambda<Func<T, T>>(op(x), x).Compile();
}

class Scan {
    StreamReader sr;
    public Scan() { sr = new StreamReader(Console.OpenStandardInput()); }
    public Scan(string path) { sr = new StreamReader(path); }
    public int Int => int.Parse(Str);
    public long Long => long.Parse(Str);
    public double Double => double.Parse(Str);
    public string Str => sr.ReadLine().Trim();
    public pair<T, U> Pair<T, U>() {
        T a; U b;
        Multi(out a, out b);
        return new pair<T, U>(a, b);
    }
    public P P => Pair<int, int>();
    public int[] IntArr => StrArr.Select(int.Parse).ToArray();
    public long[] LongArr => StrArr.Select(long.Parse).ToArray();
    public double[] DoubleArr => StrArr.Select(double.Parse).ToArray();
    public string[] StrArr => Str.Split(new[]{' '}, StringSplitOptions.RemoveEmptyEntries);
    bool eq<T, U>() => typeof(T).Equals(typeof(U));
    T ct<T, U>(U a) => (T)Convert.ChangeType(a, typeof(T));
    T cv<T>(string s) => eq<T, int>()    ? ct<T, int>(int.Parse(s))
                       : eq<T, long>()   ? ct<T, long>(long.Parse(s))
                       : eq<T, double>() ? ct<T, double>(double.Parse(s))
                       : eq<T, char>()   ? ct<T, char>(s[0])
                                         : ct<T, string>(s);
    public void Multi<T>(out T a) => a = cv<T>(Str);
    public void Multi<T, U>(out T a, out U b)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); }
    public void Multi<T, U, V>(out T a, out U b, out V c)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); }
    public void Multi<T, U, V, W>(out T a, out U b, out V c, out W d)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); }
    public void Multi<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); e = cv<X>(ar[4]); }
}

class LCATree
{
    int m;
    int[][] parent;
    long[][] dis;
    long[] distfrompar;
    int[] dep;
    public LCATree(int n, List<pair<long, int>>[] g)
    {
        parent = new int[n][];
        dis = new long[n][];
        dep = new int[n];
        distfrompar = new long[n];
        m = 1;
        while ((1 << m - 1) < n) ++m;
        for (int i = 0; i < n; i++) {
            parent[i] = new int[m];
            dis[i] = new long[m];
            dep[i] = n + 1;
            distfrompar[i]= 1L << 60;
            for (int j = 0; j < m; j++) {
                parent[i][j] = -1;
                dis[i][j] = 1L << 60;
            }
        }
        dep[0] = 0;
        distfrompar[0] = 0;
        var q = new Queue<int>();
        q.Enqueue(0);
        while (q.Count > 0) {
            var p = q.Dequeue();
            foreach (var item in g[p]) {
                if (dep[item.v2] > dep[p] + 1) {
                    dep[item.v2] = dep[p] + 1;
                    distfrompar[item.v2] = distfrompar[p] + item.v1;
                    parent[item.v2][0] = p;
                    dis[item.v2][0] = item.v1;
                    q.Enqueue(item.v2);
                }
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (dep[j] >= (1 << i)) {
                    parent[j][i] = parent[parent[j][i - 1]][i - 1];
                    dis[j][i] = Math.Min(dis[j][i], dis[parent[j][i - 1]][i - 1] + dis[j][i - 1]);
                }
            }
        }
    }
    int climb(int a, int c, out long d) {
        d = 0;
        for (int i = m - 1; i >= 0 ; i--) {
            if (((c >> i) & 1) == 1) {
                d += dis[a][i];
                a = parent[a][i];
            }
        }
        return a;
    }
    public int getLCA(int a, int b) {
        if (dep[a] < dep[b]) {
            long d;
            b = climb(b, dep[b] - dep[a], out d);
        }
        else if (dep[a] > dep[b]) {
            long d;
            a = climb(a, dep[a] - dep[b], out d);
        }
        int p = m - 1;
        while (a != b && p >= 0) {
            if (parent[a][p] != parent[b][p]) {
                a = parent[a][p];
                b = parent[b][p];
            }
            else --p;
        }
        if (a != b) {
            return parent[a][0];
        }
        return a;
    }
    public long dist(int a, int b, int lca) {
        return distfrompar[a] + distfrompar[b] - distfrompar[lca] * 2;
    }
    public long dist(int a, int b) {
        int lca = getLCA(a, b);
        return distfrompar[a] + distfrompar[b] - distfrompar[lca] * 2;
    }
}