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.IO;
using System.Linq;
using static System.Console;
using static System.Math;
using static Func;
class Z { static void Main() => new K(); }
class K
{
	int[] G => ReadLine().Split().Select(int.Parse).ToArray();
	static bool Has(ulong s, int k) => (s & (1ul << k)) != 0;
	public K()
	{
		SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		Solve();
		Out.Flush();
	}
	int N, log;
	int[] depth, depth2;
	int[,] dbl;
	List<Edge>[] g;
	Tree[] info;
	void Solve()
	{
		var I = G;
		N = I[0];
		var Q = I[1];
		g = MakeArray(N, _ => new List<Edge>());
		for (var i = 0; i < N - 1; i++)
		{
			I = G;
			g[I[0] - 1].Add(new Edge(I[1] - 1, I[2] - 1, I[3]));
			g[I[1] - 1].Add(new Edge(I[0] - 1, I[2] - 1, I[3]));
		}
		var s = new Stack<Pair>();
		s.Push(new Pair(-1, 0));
		info = MakeArray(N, _ => (Tree)null);
		depth = new int[N];
		depth2 = new int[N];
		log = (int)Ceiling(Log(N, 2) + 1);
		dbl = new int[log, N];
		info[0] = FuncT.ConstructTree(MakeArray(N - 1, c => new Info(c, 0, 0)).ToList());
		while (s.Count > 0)
		{
			var p = s.Pop();
			dbl[0, p.U] = p.P;
			foreach (var e in g[p.U])
				if (e.To != p.P) s.Push(new Pair(p.U, e.To));
				else if (p.P >= 0)
				{
					info[p.U] = info[p.P].Add(e);
					depth[p.U] = depth[p.P] + e.Length;
					depth2[p.U] = depth2[p.P] + 1;
				}
		}
		for (var l = 1; l < log; l++)
			for (var i = 0; i < N; i++)
				dbl[l, i] = dbl[l - 1, i] < 0 ? -1 : dbl[l - 1, dbl[l - 1, i]];
		for (var i = 0; i < Q; i++)
		{
			I = G;
			int c = I[0] - 1, d = I[1], u = I[2] - 1, v = I[3] - 1;
			WriteLine(Calc(c, d, u, v));
		}
	}
	int Calc(int c, int d, int u, int v)
	{
		var p = LCA(u, v);
		if (p < 0) return -1;
		var iu = info[u].Find(c).V;
		var iv = info[v].Find(c).V;
		var ip = info[p].Find(c).V;
		var cnt = iu.Count + iv.Count - 2 * ip.Count;
		var len = iu.Distance + iv.Distance - 2 * ip.Distance;
		return depth[u] + depth[v] - 2 * depth[p] - len + cnt * d;
	}
	int LCA(int u, int v)
	{
		if (depth2[u] > depth2[v]) return LCA(v, u);
		for (var l = 0; l < log; l++)
			if (Has((ulong)(depth2[v] - depth2[u]), l)) v = dbl[l, v];
		if (u == v) return u;
		for (var l = log - 1; l >= 0; l--)
			if (dbl[l, u] != dbl[l, v])
			{
				u = dbl[l, u];
				v = dbl[l, v];
			}
		return dbl[0, u];
	}
}
struct Info : IComparable<Info>
{
	public readonly int Distance, Count, Color;
	public Info(int col, int cnt, int d) { Distance = d; Count = cnt; Color = col; }

	public int CompareTo(Info other) => Color.CompareTo(other.Color);
	public static Info operator +(Info i, Edge e) => new Info(i.Color, i.Count + 1, i.Distance + e.Length);
}
struct Pair
{
	public readonly int P, U;
	public Pair(int p, int u) { P = p; U = u; }
}
struct Edge
{
	public readonly int To, Color, Length;
	public Edge(int t, int c, int l) { To = t; Color = c; Length = l; }
}
static class Func
{
	public static T[] MakeArray<T>(int n, Func<int, T> f) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = f(i); return a; }
}
class Tree
{
	public readonly Tree L, R;
	public readonly Info V;
	public readonly int H, C;
	// l < v < r and |l.h - l.r| <= 2
	public Tree(Tree l, Info v, Tree r)
	{
		C = 1 + l.Count() + r.Count();
		L = l;
		R = r;
		V = v;
		H = 1 + Max(L.Height(), R.Height());
	}
}
static class FuncT
{
	public static Tree ConstructTree(this IList<Info> list) => list.ConstructTree(0, list.Count);
	static Tree ConstructTree(this IList<Info> list, int l, int r)
	{
		if (l >= r) return null;
		var n = (l + r) / 2;
		return Join(list.ConstructTree(l, n), list[n], list.ConstructTree(n + 1, r));
	}
	public static int Count(this Tree t) => t?.C ?? 0;
	public static int Height(this Tree t) => t?.H ?? 0;
	public static Tree Find(this Tree t, int c)
	{
		if (t == null) return null;
		switch (t.V.Color.CompareTo(c))
		{
			case 1:
				return t.L.Find(c);
			case -1:
				return t.R.Find(c);
			default:
				return t;
		}
	}
	public static Tree Add(this Tree t, Edge e)
	{
		switch (t.V.Color.CompareTo(e.Color))
		{
			case 1:
				return new Tree(t.L.Add(e), t.V, t.R);
			case 0:
				return new Tree(t.L, t.V + e, t.R);
			default:
				return new Tree(t.L, t.V, t.R.Add(e));
		}
	}
	// t1 < x < t2
	public static Tree Join(Tree t1, Info x, Tree t2)
	{
		var h1 = t1.Height();
		var h2 = t2.Height();
		if (Abs(h1 - h2) <= 1) return new Tree(t1, x, t2);
		return h1 > h2 ? new Tree(t1.L, t1.V, Join(t1.R, x, t2)) : new Tree(Join(t1, x, t2.L), t2.V, t2.R);
	}
}