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: Wrong Answer)

using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using static System.Math;
using Debug = System.Diagnostics.Debug;
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;


static class P
{
    static void Main()
    {
        var n = NextInt;
        var q = NextInt;
        //更新が重い 全ての頂点間の全ての色の数を求められればいいが…
        //共通祖先のようにダブリング?
        //あるノードまでの色の数を持って
        //色が10^5種類あるため、Dictで持つと良さそう?
        //最悪ケース:全部色が違う、直線
        //平方分割すればマシになるか
        //sqrt(N)個先のあれだけ持つ 
        //そうか、一応オイラーツアーしてから適当に更新で区間和が可能か
        //更新は一度につき最悪NlogN はい 駄目
        //やっぱりLCAが一番だって いやLCAじゃん 各頂点から根までの辺色集合を持って、dist(root,v_i)+dist(root,v_j)-dist(root,LCA)
        //辺色を高速に計算したいが、空間がN+持つ区間の長さ*Nになる
        //やっぱ平方分割じゃないか
        //LCA できない どうする
        //オイラーツアーLCAが良さそう
        var neighbors = Enumerable.Repeat(0, n).Select(_ => new List<Edge>()).ToArray();
        for (int i = 0; i < n - 1; i++)
        {
            var a = NextInt - 1;
            var b = NextInt - 1;
            var c = NextInt;
            var d = NextInt;
            neighbors[a].Add(new Edge(b, c, d));
            neighbors[b].Add(new Edge(a, c, d));
        }
        Edge[] edgeToParents = new Edge[n];
        long[] distances = Enumerable.Repeat(long.MaxValue, n).ToArray();
        List<Tuple> tour = new List<Tuple>();
        int[] pointToTourIndex = Enumerable.Repeat(-1, n).ToArray();
        {
            Stack<int> stack = new Stack<int>();
            stack.Push(0);
            edgeToParents[0] = new Edge(-1, -1, -1);
            distances[0] = (1L << 40) - 1;
            while (stack.Count > 0)
            {
                var point = stack.Pop();
                tour.Add(new Tuple(point, distances[point]));
                if (pointToTourIndex[point] < 0) pointToTourIndex[point] = tour.Count - 1;
                else continue;
                foreach (var edgeToChild in neighbors[point])
                {
                    if (distances[edgeToChild.Dest] != long.MaxValue) continue;
                    var edgeToParent = edgeToChild;
                    edgeToParent.Dest = point;
                    edgeToParents[edgeToChild.Dest] = edgeToParent;
                    distances[edgeToChild.Dest] = distances[point] - edgeToChild.Distance;
                    stack.Push(point);
                    stack.Push(edgeToChild.Dest);
                }
            }
        }
        int[] edgeDestination = new int[n];
        Dictionary<int, Tuple>[] edgeUntil = new Dictionary<int, Tuple>[n];
        var sqrtLength = (int)Sqrt(n);
        for (int i = 0; i < edgeUntil.Length; i++)
        {
            Dictionary<int, Tuple> res = new Dictionary<int, Tuple>();
            int currentPoint = i;
            for (int iteration = 0; iteration < sqrtLength; iteration++)
            {
                var edgeToParent = edgeToParents[currentPoint];
                if (edgeToParent.Dest < 0) break;
                if (!res.ContainsKey(edgeToParent.Color)) res.Add(edgeToParent.Color, new Tuple(0, 0));
                var item = res[edgeToParent.Color];
                item.Item1++;
                item.Item2 += edgeToParent.Distance;
                res[edgeToParent.Color] = item;
                currentPoint = edgeToParent.Dest;
            }
            edgeDestination[i] = currentPoint;
            edgeUntil[i] = res;
        }
        SegmentTree<Tuple> segTree = new SegmentTree<Tuple>(tour.ToArray(), new Tuple(0, 0), (x, y) => x.Item2 < y.Item2 ? y : x);
        StringBuilder builder = new StringBuilder();
        return;
        for (int i = 0; i < q; i++)
        {
            var color = NextInt;
            var distanceChangeTo = NextInt;
            var a = NextInt - 1;
            var b = NextInt - 1;
            //LCAを求める
            //オイラーツアーの一対一対応が必要そう
            var LCA = segTree.Query(pointToTourIndex[a], pointToTourIndex[b]).Item1;
            //二頂点間の距離を求める(dist(a)+dist(b)-dist(LCA)*2)
            var dist = -(distances[a] + distances[b] - distances[LCA] * 2);
            //に頂点間の色の数を求める(countEdgeUntilを0になるまでたどり、う)
            var aColor = GetColorLength(a, color, edgeUntil, edgeDestination);
            var bColor = GetColorLength(b, color, edgeUntil, edgeDestination);
            var LCAColor = GetColorLength(LCA, color, edgeUntil, edgeDestination);
            var colorCount = aColor.Item1 + bColor.Item1 - LCAColor.Item1 * 2;
            var colorDistance = aColor.Item2 + bColor.Item2 - LCAColor.Item2 * 2;
            var res = dist - colorDistance + distanceChangeTo * colorCount;

            builder.AppendLine(res.ToString());
        }
        Console.WriteLine(builder.ToString());
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static Tuple<int, long> GetColorLength(int a, int color, Dictionary<int, Tuple>[] countEdgeUntil, int[] edgeDestination)
    {
        int count = 0;
        long distance = 0;
        while (a != 0)
        {
            if (countEdgeUntil[a].ContainsKey(color))
            {
                count += countEdgeUntil[a][color].Item1;
                distance += countEdgeUntil[a][color].Item2;
            }
            a = edgeDestination[a];
        }
        return new Tuple<int, long>(count, distance);
    }

    static readonly TextReader In = Console.In;
    static int NextInt
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get
        {
            int res = 0;
            int next = In.Read();
            int rev = 1;
            while (45 > next || next > 57) next = In.Read();
            if (next == 45) { next = In.Read(); rev = -1; }
            while (48 <= next && next <= 57)
            {
                res = res * 10 + next - 48;
                next = In.Read();
            }
            return res * rev;
        }
    }
}

struct Tuple
{
    public int Item1;
    public long Item2;
    public Tuple(int item1, long item2)
    {
        Item1 = item1;
        Item2 = item2;
    }
}

struct Edge
{
    public int Dest;
    public int Color;
    public long Distance;
    public Edge(int dest, int color, int distance)
    {
        Dest = dest;
        Color = color;
        Distance = distance;
    }
}

class SegmentTree<T>
{
    public int Size { get; private set; }
    T IdentityElement;
    T[] Data;
    Func<T, T, T> Merge;
    int LeafCount;

    public SegmentTree(int size, T identityElement, Func<T, T, T> merge) : this(Enumerable.Repeat(identityElement, size).ToArray(), identityElement, merge) { }

    public SegmentTree(T[] elems, T identityElement, Func<T, T, T> merge)
    {
        Size = elems.Length;
        Merge = merge;
        IdentityElement = identityElement;
        LeafCount = 1;
        while (LeafCount < elems.Length) LeafCount <<= 1;

        Data = new T[LeafCount * 2];
        elems.CopyTo(Data, LeafCount);
        for (int i = LeafCount - 1; i >= 1; i--) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    public T this[int index]
    {
        get { return Data[LeafCount + index]; }
        set { Update(index, value); }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Update(int i, T x)
    {
        i += LeafCount;
        Data[i] = x;
        while (0 < (i >>= 1)) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Operate(int i, T x)
    {
        i += LeafCount;
        Data[i] = Merge(Data[i], x);
        while (0 < (i >>= 1)) Data[i] = Merge(Data[i * 2], Data[i * 2 + 1]);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T Query(int l, int r)
    {
        l += LeafCount;
        T lRes = IdentityElement;
        r += LeafCount;
        T rRes = IdentityElement;
        while (l <= r)
        {
            if (l % 2 == 1) lRes = Merge(lRes, Data[l]);
            if (r % 2 == 0) rRes = Merge(Data[r], rRes);
            l = (l + 1) / 2;
            r = (r - 1) / 2;
        }
        return Merge(lRes, rRes);
    }
}