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.IO;
using SB = System.Text.StringBuilder;
//using System.Threading.Tasks;
//using System.Text.RegularExpressions;
//using System.Globalization;
//using System.Diagnostics;
using static System.Console;
using System.Numerics;
using static System.Math;
using pair = Pair<int, int>;

class Program
{
    static void Main()
    {
        //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
        new Program().solve();
        Out.Flush();
    }
    readonly Scanner cin = new Scanner();
    readonly int[] dd = { 0, 1, 0, -1, 0 }; //→↓←↑
    readonly int mod = 1000000007;
    readonly int dom = 998244353;
    bool chmax<T>(ref T a, T b) where T : IComparable<T> { if (a.CompareTo(b) < 0) { a = b; return true; } return false; }
    bool chmin<T>(ref T a, T b) where T : IComparable<T> { if (b.CompareTo(a) < 0) { a = b; return true; } return false; }

    class Edge : IComparable<Edge>
    {
        public int from, to, id; public long cost;
        public Edge(int from, int to, long cost, int id = -1)
        {
            this.from = from;
            this.to = to;
            this.cost = cost;
            this.id = id;
        }
        public int CompareTo(Edge e) => cost.CompareTo(e.cost);
    }
    List<Edge>[] G;
    int[] num;
    long[] cost;
    List<int>[] need;
    HashMap<int, Data>[] data;
    void solve()
    {
        int N = cin.nextint;
        int Q = cin.nextint;
        var A = new int[N - 1];
        var B = new int[N - 1];
        var C = new int[N - 1];
        var D = new int[N - 1];

        G = new List<Edge>[N];
        data = new HashMap<int, Data>[N];
        need = new List<int>[N];

        for (int i = 0; i < N; i++)
        {
            G[i] = new List<Edge>();
            need[i] = new List<int>();
            data[i] = new HashMap<int, Data>();
        }
        var LCA = new HLTree(N);
        for (int i = 0; i < N - 1; i++)
        {
            A[i] = cin.nextint - 1;
            B[i] = cin.nextint - 1;
            C[i] = cin.nextint - 1;
            D[i] = cin.nextint;
            LCA.AddEdge(A[i], B[i]);
            G[A[i]].Add(new Edge(A[i], B[i], D[i], C[i]));
            G[B[i]].Add(new Edge(B[i], A[i], D[i], C[i]));
        }
        LCA.Build();

        var X = new int[Q];
        var Y = new int[Q];
        var U = new int[Q];
        var V = new int[Q];
        for (int i = 0; i < Q; i++)
        {
            X[i] = cin.nextint - 1;
            Y[i] = cin.nextint;
            U[i] = cin.nextint - 1;
            V[i] = cin.nextint - 1;
            need[U[i]].Add(X[i]);
            need[V[i]].Add(X[i]);
            need[LCA.GetLCA(U[i], V[i])].Add(X[i]);
        }
        
        num = new int[N - 1];
        cost = new long[N - 1];
        dfs(0, -1, 0);

        for (int i = 0; i < Q; i++)
        {
            var u = dist(U[i], X[i], Y[i]);
            var v = dist(V[i], X[i], Y[i]);
            var lca = dist(LCA.GetLCA(U[i], V[i]), X[i], Y[i]);
            WriteLine(u + v - 2 * lca);
        }
    }

    long dist(int u, int c, int y)
    {
        return data[u][c].dist - data[u][c].cost + data[u][c].num * y;
    }
    void dfs(int u, int par, long dist)
    {
        foreach (var c in need[u])
        {
            data[u][c] = new Data(dist, num[c], cost[c]);
        }
        foreach (var v in G[u])
        {
            if (v.to == par) continue;
            num[v.id]++;
            cost[v.id] += v.cost;
            dfs(v.to, u, dist + v.cost);
            num[v.id]--;
            cost[v.id] -= v.cost;
        }
    }
    class Data
    {
        public long dist;
        public long num;
        public long cost;
        public Data(long b, long c, long d)
        {
            dist = b;
            num = c;
            cost = d;
        }
    }

}

class HashMap<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set
        {
            base[key] = value;
        }
    }
}

/// <OriginalAuthor>camypaper</OriginalAuthor>
class HLTree
{
    readonly int n;
    readonly List<int>[] G;
    readonly int[] subtreeSize;
    readonly int[] maxsize;
    readonly int[] par;
    readonly int[] depth;
    readonly Chain[] go;
    readonly int[] pos;
    List<Chain> chains;
    public HLTree(int N)
    {
        n = N;
        G = new List<int>[n];
        chains = new List<Chain>();
        for (int i = 0; i < n; i++)
            G[i] = new List<int>();
        subtreeSize = new int[n];
        maxsize = new int[n];
        par = new int[n];
        depth = new int[n];
        go = new Chain[n];
        pos = new int[n];
    }
    public void AddEdge(int u, int v)
    {
        G[u].Add(v); G[v].Add(u);
    }
    public void Build(int root = 0)
    {
        computeSubtreeSize(root);
        Decomposite(-1, root, 0);
    }
    void computeSubtreeSize(int r)
    {
        var stack = new Stack<int>();
        stack.Push(r);
        var iter = new int[n];
        par[r] = -1;
        //dfs
        while (stack.Count > 0)
        {
            var cur = stack.Peek();
            if (iter[cur] == G[cur].Count)
            {
                stack.Pop();
                subtreeSize[cur]++;
                if (par[cur] != -1)
                {
                    subtreeSize[par[cur]] += subtreeSize[cur];
                    maxsize[par[cur]] = Math.Max(maxsize[par[cur]], subtreeSize[cur]);
                }
                continue;
            }
            var next = G[cur][iter[cur]++];
            if (next == par[cur]) continue;
            par[next] = cur;
            depth[next] = depth[cur] + 1;
            stack.Push(next);
        }

    }
    void Decomposite(int from, int cur, int lv)
    {
        var chain = new Chain(from, lv);
        chains.Add(chain);
        chain.Add(cur);
        while (cur != from)
        {
            var next = cur;
            go[cur] = chain;
            pos[cur] = chain.Count;
            foreach (var to in G[cur])
            {
                if (to == from) continue;
                if (maxsize[cur] == subtreeSize[to])
                {
                    maxsize[cur] = -1;
                    next = to;
                    chain.Add(to);
                }
                else Decomposite(cur, to, lv + 1);
            }

            from = cur;
            cur = next;

        }
        chain.Init();

    }
    // 頂点aから頂点bへの距離は depth(a) + depth(b) - 2 * depth(lca(a, b))
    public int GetLCA(int u, int v)
    {
        while (go[u] != go[v])
        {
            if (go[u].Level < go[v].Level) v = go[v].From;
            else u = go[u].From;
        }
        if (depth[u] <= depth[v]) return u;
        else return v;
    }
    public int this[int u]
    {
        get { return depth[u]; }
    }
}

class Chain
{
    public int From { get; set; }
    public int Level { get; set; }
    public int Count { get; private set; }
    List<int> heavy;
    public Chain(int from, int lv)
    {
        From = from;
        Level = lv;
        heavy = new List<int>();
    }
    public void Add(int v)
    {
        //heavy.Add(v);
        Count++;
    }
    public void Init()
    {

    }
}

static class Ex
{
    public static void join<T>(this IEnumerable<T> values, string sep = " ") => WriteLine(string.Join(sep, values));
    public static string concat<T>(this IEnumerable<T> values) => string.Concat(values);
    public static string reverse(this string s) { var t = s.ToCharArray(); Array.Reverse(t); return t.concat(); }

    public static int lower_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) < 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
    public static int upper_bound<T>(this IList<T> arr, T val) where T : IComparable<T>
    {
        int low = 0, high = arr.Count;
        int mid;
        while (low < high)
        {
            mid = ((high - low) >> 1) + low;
            if (arr[mid].CompareTo(val) <= 0) low = mid + 1;
            else high = mid;
        }
        return low;
    }
}

class Pair<T, U> : IComparable<Pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T f; public U s;
    public Pair(T f, U s) { this.f = f; this.s = s; }
    public int CompareTo(Pair<T, U> a) => f.CompareTo(a.f) != 0 ? f.CompareTo(a.f) : s.CompareTo(a.s);
    public override string ToString() => $"{f} {s}";
}

class Scanner
{
    string[] s; int i;
    readonly char[] cs = new char[] { ' ' };
    public Scanner() { s = new string[0]; i = 0; }
    public string[] scan => ReadLine().Split();
    public int[] scanint => Array.ConvertAll(scan, int.Parse);
    public long[] scanlong => Array.ConvertAll(scan, long.Parse);
    public double[] scandouble => Array.ConvertAll(scan, double.Parse);
    public string next
    {
        get
        {
            if (i < s.Length) return s[i++];
            string st = ReadLine();
            while (st == "") st = ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
            return next;
        }
    }
    public int nextint => int.Parse(next);
    public long nextlong => long.Parse(next);
    public double nextdouble => double.Parse(next);
}