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: Runtime Error)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace ConsoleApplication2
{
    // ２次元Dictionary(key1とkey2に意味を持たない)
    class Hash2DimS<Tkey, TVal>
    {
        Hash2DimL<Tkey, Tkey, TVal> dic;
        public Hash2DimS()
        {
            dic = new Hash2DimL<Tkey, Tkey, TVal>();
        }

        public TVal this[Tkey i1, Tkey i2]
        {
            set { this.Add(i1, i2, value); }
            get { return this.Get(i1, i2); }
        }
        private TVal Get(Tkey key1, Tkey key2)
        {
            if (dic.ContainsKey(key1, key2))
            {
                return dic[key1, key2];
            }
            if (dic.ContainsKey(key2, key1))
            {
                return dic[key2, key1];
            }


            return default(TVal);
        }
        private void Add(Tkey key1, Tkey key2, TVal val)
        {
            dic[key1, key2] = val;
        }
        public bool ContainsKey(Tkey key1, Tkey key2)
        {
            if (dic.ContainsKey(key1, key2)) return true;
            if (dic.ContainsKey(key2, key1)) return true;
            return false;
        }
    }
    // ２次元DictionaryAddは上書き(key1とkey2に意味を持つ)
    class Hash2DimL<Tkey1, Tkey2, TVal>
    {
        Dictionary<Tkey1, Dictionary<Tkey2, TVal>> d1;
        public Hash2DimL()
        {
            d1 = new Dictionary<Tkey1, Dictionary<Tkey2, TVal>>();
        }
        public TVal this[Tkey1 i1, Tkey2 i2]
        {
            set { this.Add(i1, i2, value); }
            get { return this.Get(i1,i2); }
        }
        private TVal Get(Tkey1 key1, Tkey2 key2)
        {
            if (!ContainsKey(key1, key2)) return default(TVal);
            return d1[key1][key2];
        }
        private void Add(Tkey1 key1, Tkey2 key2, TVal val)
        {
            if (d1.ContainsKey(key1))
            {
                Dictionary<Tkey2, TVal> d2 = d1[key1];
                d2.Add(key2, val);
            }
            else
            {
                Dictionary<Tkey2, TVal> d2 = new Dictionary<Tkey2, TVal>();
                d2.Add(key2, val);
                d1.Add(key1, d2);
            }
        }
        public bool ContainsKey(Tkey1 key1, Tkey2 key2)
        {
            if (d1.ContainsKey(key1))
            {
                Dictionary<Tkey2, TVal> d2 = d1[key1];
                if (d2.ContainsKey(key2))
                {
                    return true;
                }
                return false;
            }
            else
            {
                return false;
            }

        }
    }
    class edge
    {
        public long n1;
        public long n2;
        public long dist;
        public long color;
        public edge(string[] inp)
        {
            n1 = long.Parse(inp[0]);
            n2 = long.Parse(inp[1]);
            color = long.Parse(inp[2]);
            dist = long.Parse(inp[3]);
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            //*
            var exStdIn = new System.IO.StreamReader("stdin.txt");
            System.Console.SetIn(exStdIn);
            //*/
            string[] input = Console.ReadLine().Split(' ');
            long n = long.Parse(input[0]);
            long q = long.Parse(input[1]);
            edge[] edges = new edge[n-1];//すべての辺

            List<long>[] tree = new List<long>[n + 1];
            List<edge>[] edgeRoot = new List<edge>[n + 1];
            List<long>[] nodeRoot = new List<long>[n + 1];

            //初期化
            for (long i = 1; i < n + 1; i++) tree[i] = new List<long>();
            for (long i = 1; i < n + 1; i++) edgeRoot[i] = new List<edge>();
            for (long i = 1; i < n + 1; i++) nodeRoot[i] = new List<long>();

            Hash2DimS<long, edge> hash = new Hash2DimS<long, edge>();
            
            for (long i = 0; i < n - 1; i++)
            {
                input = Console.ReadLine().Split(' ');
                edges[i] = new edge(input);

                tree[edges[i].n1].Add(edges[i].n2);
                tree[edges[i].n2].Add(edges[i].n1);

                hash[edges[i].n1, edges[i].n2] = edges[i];
            }
            //ルートからiに至るまでのノードをすべて記憶
            method(0, 1, tree, nodeRoot, null);

            for (long i = 0; i < q; i++)
            {
                input = Console.ReadLine().Split(' ');
                long x = long.Parse(input[0]);
                long y = long.Parse(input[1]);
                long u = long.Parse(input[2]);
                long v = long.Parse(input[3]);

                int common = 1;
                //共通部スキップ
                for(int c = 0; c < Math.Min(nodeRoot[u].Count, nodeRoot[u].Count); c++)
                {

                    if(nodeRoot[u][c] == nodeRoot[v][c])
                    {
                        common = c;
                    }
                    else
                    {
                        break;
                    }
                }
                long distU = 0;
                for (int j = common; j < nodeRoot[u].Count - 1; j++)
                {
                    long n1 = nodeRoot[u][j];
                    long n2 = nodeRoot[u][j+1];
                    if (hash[n1, n2].color == x)
                    {
                        distU += y;
                    }
                    else
                    {
                        distU += hash[n1, n2].dist;
                    }

                }
                long distV = 0;
                for (int j = common; j < nodeRoot[v].Count - 1; j++)
                {
                    long n1 = nodeRoot[v][j];
                    long n2 = nodeRoot[v][j + 1];
                    if (hash[n1, n2].color == x)
                    {
                        distV += y;
                    }
                    else
                    {
                        distV += hash[n1, n2].dist;
                    }

                }


                Console.WriteLine(distV+ distU);

            }
            
            //Console.WriteLine(string.Join(" ", b));
        }

        //親、親までのリスト
        private static void method(long p,long tar, List<long>[] tree, List<long>[] nodeRoot, List<long> fromRoot)
        {
            if (fromRoot != null)
            {
                foreach (long fr in fromRoot)
                {
                    nodeRoot[tar].Add(fr);
                }
            }
            nodeRoot[tar].Add(tar);

            List<long> children = tree[tar];
            foreach (long ch in children)
            {
                if (ch != p)
                {
                    method(tar, ch, tree, nodeRoot, nodeRoot[tar]);
                }
            }
        }

        // uからvまでの距離を返す。子孫にwがいなければ-1を返す
        static long func(long p,long u, long v, List<long>[] tree, edge[] edges, Hash2DimS<long, edge> hash, long color, long dist)
        {
            long sum = 0;
            List<long> chirdren = tree[u];
            foreach (long ch in chirdren)
            {
                if (ch == v)
                {
                    edge e = hash[u, v];
                    if (e.color == color)
                    {
                        sum += dist;
                    }
                    else
                    {
                        sum += e.dist;
                    }
                    return sum;
                }
                else if (ch != p)//親に戻らないように
                {
                    long a = func(u, ch, v, tree, edges, hash, color, dist);
                    if (a > -1)
                    {
                        edge e = hash[u, ch];
                        if (e.color == color)
                        {
                            sum += dist;
                        }
                        else
                        {
                            sum += e.dist;
                        }
                        return sum + a;
                    }
                }
            }
            return -1;
        }
    }
}