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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading.Tasks;
using static System.Console;
using static System.Math;
using static Func;
using static FuncT;
class Z { static void Main() => new K(); }
class K
{
	int F => int.Parse(Str);
	long FL => long.Parse(Str);
	int[] G => Strs.Select(int.Parse).ToArray();
	uint[] GU => Strs.Select(uint.Parse).ToArray();
	decimal[] GD => Strs.Select(decimal.Parse).ToArray();
	long[] GL => Strs.Select(long.Parse).ToArray();
	string Str => ReadLine();
	string[] Strs => Str.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
	static ulong One(int k) => 1ul << k;
	static ulong All(int k) => One(k) - 1;
	static bool Has(ulong s, int k) => (s & One(k)) != 0;
	const int MOD = 1000000007;
	public K()
	{
		SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		Solve();
		Out.Flush();
	}
	int N, log;
	int[] depth, depth2;
	int[,] dbl;
	List<Edge>[] g;
	Tree<Info>[] 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<Info>)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 u in g[p.U])
				if (u.To != p.P) s.Push(new Pair(p.U, u.To));
				else if (p.P >= 0)
				{
					var t = info[p.P].Find(new Info(u.Color, 0, 0)).V;
					t = new Info(t.Color, t.Count + 1, t.Distance + u.Length);
					info[p.U] = info[p.P].Add(t);
					depth[p.U] = depth[p.P] + u.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);
		var iu = info[u].Find(new Info(c, 0, 0)).V;
		var iv = info[v].Find(new Info(c, 0, 0)).V;
		var ip = info[p].Find(new Info(c, 0, 0)).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 override string ToString() => $"Info(col={Color},cnt={Count},d={Distance})";
}
struct Pair
{
	public readonly int P, U;
	public Pair(int p, int u) { P = p; U = u; }
	public override string ToString() => $"Pair(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; }
	public override string ToString() => $"Edge(t={To},c={Color},l={Length})";
}
static class Func
{
	public static T[] ConstantArray<T>(int n, T val) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = val; return a; }
	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; }
	public static T[] Recurse<T>(int n, T a0, Func<int, T, T> f) { var a = new T[n]; a[0] = a0; for (var i = 1; i < n; i++) a[i] = f(i, a[i - 1]); return a; }
	public static T[] Accumulate<T>(IList<T> a, T zero, Func<T, T, T> f) { var s = new T[a.Count + 1]; s[0] = zero; for (var i = 0; i < a.Count; i++) s[i + 1] = f(s[i], a[i]); return s; }
	public static int FirstBinary(int min, int max, Predicate<int> pred)
	{
		while (min < max)
		{
			var mid = (min + max) / 2;
			if (pred(mid)) max = mid;
			else min = mid + 1;
		}
		return min;
	}
	public static long GCD(long a, long b)
	{
		var n = (ulong)Math.Abs(a); var m = (ulong)Math.Abs(b);
		if (n == 0) return (long)m; if (m == 0) return (long)n;
		int zm = 0, zn = 0;
		while ((n & 1) == 0) { n >>= 1; zn++; }
		while ((m & 1) == 0) { m >>= 1; zm++; }
		while (m != n)
		{
			if (m > n) { m -= n; while ((m & 1) == 0) m >>= 1; }
			else { n -= m; while ((n & 1) == 0) n >>= 1; }
		}
		return (long)n << Math.Min(zm, zn);
	}
	public static long Inverse(long a, long mod)
	{
		if (a < 0) { a %= mod; if (a < 0) a += mod; }
		var t = SolveLinear(a, mod);
		return t.Item1 > 0 ? t.Item1 : t.Item1 + mod;
	}
	public static long Pow(long a, long b, long mod)
	{
		var p = 1L;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p = (p * x) % mod;
			b >>= 1;
			x = (x * x) % mod;
		}
		return p;
	}
	public static Tuple<long, long> SolveLinear(long n, long m)
	{
		if (n < 0) { var p = SolveLinear(-n, m); return p == null ? p : new Tuple<long, long>(-p.Item1, p.Item2); }
		if (m < 0) { var p = SolveLinear(n, -m); return p == null ? p : new Tuple<long, long>(p.Item1, -p.Item2); }
		if (n < m) { var p = SolveLinear(m, n); return p == null ? p : new Tuple<long, long>(p.Item2, p.Item1); }
		long a = 1, b = 0, c = 0, d = 1;
		while (m > 0)
		{
			var r = n % m;
			var q = n / m;
			n = m;
			m = r;
			var tmp = a;
			a = -a * q + b;
			b = tmp;
			tmp = c;
			c = -c * q + d;
			d = tmp;
		}
		return n != 1 ? null : new Tuple<long, long>(d, b);
	}
}
class Tree<T> where T : IComparable<T>
{
	public readonly Tree<T> L, R;
	public readonly T V;
	public readonly int H, C;
	// l < v < r and |l.h - l.r| <= 2
	public Tree(Tree<T> l, T v, Tree<T> r)
	{
		C = 1 + l.Count() + r.Count();
		L = l;
		R = r;
		V = v;
		H = 1 + Max(L.Height(), R.Height());
	}
	public override string ToString() => FuncT.ToString(this);
}
static class FuncT
{
	public static Tree<T> ConstructTree<T>(this IList<T> list) where T : IComparable<T> => list.ConstructTree(0, list.Count);
	static Tree<T> ConstructTree<T>(this IList<T> list, int l, int r) where T : IComparable<T>
	{
		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 string ToString<T>(this Tree<T> t) where T : IComparable<T> => t == null ? "[Empty]\n" : ToString(t, 0);
	static string ToString<T>(this Tree<T> t, int depth) where T : IComparable<T>
	{
		if (t == null) return "";
		var sb = new StringBuilder();
		sb.Append(t.L.ToString(depth + 1));
		sb.Append(' ', 2 * depth);
		sb.AppendFormat("{0} - {1} - {2}\n", t.V, t.H, t.C);
		sb.Append(t.R.ToString(depth + 1));
		return sb.ToString();
	}
	public static int Count<T>(this Tree<T> t) where T : IComparable<T> => t?.C ?? 0;
	public static int Height<T>(this Tree<T> t) where T : IComparable<T> => t?.H ?? 0;
	public static Tree<T> Find<T>(this Tree<T> t, T x) where T : IComparable<T>
	{
		if (t == null) return null;
		switch (t.V.CompareTo(x))
		{
			case 1:
				return t.L.Find(x);
			case -1:
				return t.R.Find(x);
			default:
				return t;
		}
	}
	public static Tree<T> Add<T>(this Tree<T> t, T x) where T : IComparable<T>
	{
		if (t == null) return new Tree<T>(null, x, null);
		switch (t.V.CompareTo(x))
		{
			case 1:
				return new Tree<T>(t.L.Add(x), t.V, t.R);
			case 0:
				return new Tree<T>(t.L, x, t.R);
			default:
				return new Tree<T>(t.L, t.V, t.R.Add(x));
		}
	}
	// t1 < x < t2
	public static Tree<T> Join<T>(Tree<T> t1, T x, Tree<T> t2) where T : IComparable<T>
	{
		var h1 = t1.Height();
		var h2 = t2.Height();
		if (Math.Abs(h1 - h2) <= 1) return new Tree<T>(t1, x, t2);
		return h1 > h2 ? new Tree<T>(t1.L, t1.V, Join(t1.R, x, t2)) : new Tree<T>(Join(t1, x, t2.L), t2.V, t2.R);
	}
}