//include
//------------------------------------------
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>

#include <numeric>
#include <utility>
#include <complex>

#include <sstream>
#include <iostream>
#include <iomanip>

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <ctime>

// namespace
using namespace std;

// type alias
using ll = long long;
using ull = unsigned long long;
using comp = complex<double>;

// constant
static const ll MOD = 998244353LL;
static const double PI = 3.14159265358979323846;

// conversion
inline ll toint(string s) { ll v; istringstream sin(s); sin >> v; return v; }
template<class t> inline string tostring(t x) { ostringstream sout; sout << x; return sout.str(); }

// print
#define RET(x) return cout << x << endl, 0;

// for loop
#define REP(i, a, b) for ((i) = (ll)(a);(i) < (ll)(b);(i)++)
#define REPD(i, a, b) for (ll i = (ll)(a);(i) < (ll)(b);(i)++)
#define REPI(v, vs) for (auto& v : vs)

//debug
#ifdef LOCAL_ENV
#define DUMP(x)  cerr << #x << " = " << (x) << endl
#define DEBUG(x) cerr << #x << " = " << (x) << " (l" << __LINE__ << ")" << " " << __FILE__ << endl
#else
#define DUMP(x)
#define DEBUG(x)
#endif

#define MAX_VALUE 9223372036854775807LL

template <ull N, class T, class... Args, std::enable_if_t<N == 0, int> = 0>
auto make_multiple_vector(Args... args) {
    return T(args...);
}

template <ull N, class T, class... Args, std::enable_if_t<N != 0, int> = 0>
auto make_multiple_vector(ull size, Args... args) {
    using value_type = std::decay_t<decltype(make_multiple_vector<N - 1, T>(args...))>;
    return vector<value_type>(size, make_multiple_vector<N - 1, T>(args...));
}



template <class EdgeInfo>
struct Graph {
	using Vertex = ll;
	using Edge = tuple<Vertex, Vertex, EdgeInfo>;
	ll vertex_count;
	vector<Edge> edges;

	Graph() : vertex_count(0LL), edges(0LL) {}
	Graph(ll vertex_count) : vertex_count(vertex_count), edges(0LL) {}

	void add_edge(Vertex from, Vertex to, EdgeInfo edge_info)
	{
		edges.emplace_back(from, to, edge_info);
	}

	void add_edge(Vertex from, Vertex to)
	{
		edges.emplace_back(from, to, EdgeInfo());
	}

	vector<vector<Edge>> get_adjacency_list() const
	{
		// 辺の隣接リストを作成
		vector<vector<Edge>> adjancency_list(vertex_count);
		for (ll i = 0; i < edges.size(); ++i)
		{
			Vertex from, to;
			EdgeInfo info;
			tie(from, to, info) = edges[i];
			adjancency_list[from].emplace_back(from, to, info);
		}
		return move(adjancency_list);
	}

	vector<vector<Vertex>> get_adjacency_list_with_no_info() const
	{
		// 辺の隣接リストを作成
		vector<vector<Vertex>> adjancency_list(vertex_count);
		for (ll i = 0; i < edges.size(); ++i)
		{
			Vertex from, to;
			EdgeInfo info;
			tie(from, to, info) = edges[i];
			adjancency_list[from].emplace_back(to);
		}
		return move(adjancency_list);
	}
};

// 始点 s から各点への最短距離を返します。
// パス自体が存在しない場合は -1 を返します。
// 距離 lengths の各要素にとくに条件はありません。
// 長さが負となる経路が存在しない場合を想定しており、負経路が存在するかは別の方法で検出する必要があります。
pair<vector<ll>, vector<ll>> bellman_ford(const Graph<ll>& graph, ll s = 0LL)
{
	using Vertex = ll;
	using Length = ll;

	// アルゴリズム本体
	vector<Length> dists(graph.vertex_count, 1LL << 60);
	vector<Vertex> prev_vertices(graph.vertex_count, -1LL);

	dists[s] = 0LL;
	prev_vertices[s] = s;
	ll from, to, length;
	for (ll i = 0; i + 1 < graph.vertex_count; ++i)
	{
		for (ll j = 0; j < graph.edges.size(); ++j)
		{
			auto& edge = graph.edges[j];
			tie(from, to, length) = edge;
			if (dists[to] > dists[from] + length)
			{
				dists[to] = min(dists[to], dists[from] + length);
				prev_vertices[to] = from;
			}
		}
	}

	return { dists, prev_vertices };
}

template<class EdgeInfo>
Graph<EdgeInfo> get_rooted_bfs_tree_graph(const Graph<EdgeInfo>& graph, ll r = 0LL)
{
	Graph<EdgeInfo> rooted_tree(graph.vertex_count);
	auto adjacency_list = graph.get_adjacency_list();

	queue<ll> queue;
	vector<bool> have_checked(graph.vertex_count);

	queue.push(r);
	have_checked[r] = true;
	ll from, to;
	EdgeInfo info;
	while (!queue.empty())
	{
		from = queue.front();
		queue.pop();
		for (auto& edge : adjacency_list[from])
		{
			tie(from, to, info) = edge;
			if (have_checked[to])
				continue;
			rooted_tree.add_edge(from, to, info);
			queue.push(to);
			have_checked[to] = true;
		}
	}

	return rooted_tree;
}

class TreeLCACalculator
{
private:
	vector<vector<ll>> parent_by_power2;
	vector<ll> depths;
public:
	TreeLCACalculator(ll node_count, const vector<vector<ll>>& edges, ll s = 0LL) :
		parent_by_power2(node_count), depths(node_count)
	{
		ll log_n = 0;
		while ((node_count >> (log_n + 1LL)) > 0)
		{
			++log_n;
		}

		vector<bool> have_checked(node_count, false);
		queue<ll> queue;

		queue.emplace(s);
		depths[s] = 0;
		parent_by_power2[s].resize(log_n + 2LL, s);
		have_checked[s] = true;

		ll from, to;
		while (!queue.empty())
		{
			from = queue.front();
			queue.pop();

			for (auto& edge : edges[from])
			{
				to = edge;
				if (have_checked[to])
					continue;

				depths[to] = depths[from] + 1;
				parent_by_power2[to].resize(log_n + 2LL, s);
				parent_by_power2[to][0] = from;
				for (ll i = 0; i + 1 < log_n + 2LL; ++i)
				{
					parent_by_power2[to][i + 1] = parent_by_power2[parent_by_power2[to][i]][i];
				}
				queue.push(to);
				have_checked[to] = true;
			}
		}
	}

	ll calculate(ll node1, ll node2) {

		auto get_index = [](ull a)
		{
			ll index = -1;
			for (; a != 0; a >>= 1)
			{
				++index;
			}
			return index;
		};

		if (depths[node1] < depths[node2])
		{
			auto tmp = node1;
			node1 = node2;
			node2 = tmp;
		}
		if (depths[node1] > depths[node2])
		{
			auto diff = depths[node1] - depths[node2];
			while (diff > 0)
			{
				node1 = parent_by_power2[node1][get_index(diff & -diff)];
				diff -= diff & -diff;
			}
		}

		if (node1 == node2)
			return node1;

		const ll sz = parent_by_power2[node1].size();
		for (ll i = 0; i < sz; ++i)
		{
			if (parent_by_power2[node1][sz - i - 1] != parent_by_power2[node2][sz - i - 1])
			{
				node1 = parent_by_power2[node1][sz - i - 1];
				node2 = parent_by_power2[node2][sz - i - 1];
			}
		}

		return parent_by_power2[node1][0];
	}
};

template<class EdgeInfo>
pair<vector<pair<tuple<ll, ll, EdgeInfo>, string>>, vector<pair<ll, ll>>>
get_euler_tour(const Graph<EdgeInfo>& rooted_tree, ll r)
{
	using Vertex = ll;
	using Edge = tuple<Vertex, Vertex, EdgeInfo>;
	auto adjacent_list = rooted_tree.get_adjacency_list();

	// DFS
	struct EulerTourCalculator
	{
		const vector<vector<Edge>> adjacency_list;
		vector<bool> have_checked;
		vector<Edge> prev_edges;
		vector<pair<Edge, string>> euler_tour;

		EulerTourCalculator(const vector<vector<Edge>>& adjacency_list, ll r) :
			adjacency_list(adjacency_list),
			have_checked(adjacency_list.size(), false),
			prev_edges(adjacency_list.size())
		{
			have_checked[r] = true;
			get<0>(prev_edges[r]) = -1LL;
			get<1>(prev_edges[r]) = r;
			call(r);
		}

		void call(ll from)
		{
			for (const auto& edge : adjacency_list[from])
			{
				ll to = get<1>(edge);

				if (have_checked[to])
					continue;

				have_checked[to] = true;
				prev_edges[to] = edge;
				euler_tour.emplace_back(edge, "+");
				call(to);
			}
			euler_tour.emplace_back(prev_edges[from], "-");
		}
	};

	auto euler_tour = EulerTourCalculator(adjacent_list, r).euler_tour;
	euler_tour.pop_back();

	vector<pair<ll, ll>> tour_index(rooted_tree.vertex_count, { -1, -1 });
	tour_index[r].first = 0LL;
	for (ll i = 0; i < euler_tour.size(); ++i)
	{
		Edge edge;
		string type;
		tie(edge, type) = euler_tour[i];
		ll from = get<0>(edge), to = get<1>(edge);

		if (type == "+" && tour_index[to].first == -1)
		{
			tour_index[to].first = i + 1;
		}
		else if (type == "-" && tour_index[to].second == -1)
		{
			tour_index[to].second = i;
		}
	}

	return { euler_tour, tour_index };
}



int solve() {
	ll N, Q;
	cin >> N >> Q;
	ll a, b, c, d, x, y, u, v;
    Graph<pair<ll, ll>> g(N);
    REPD(i, 1, N) {
		cin >> a >> b >> c >> d;
		--a, --b;
		g.add_edge(a, b, {c, d});
		g.add_edge(b, a, {c, d});
	}
	auto rooted = get_rooted_bfs_tree_graph(g);
	TreeLCACalculator lca(N, g.get_adjacency_list_with_no_info());

	vector<ll> lengths(N);
	auto euler_tour = get_euler_tour(rooted, 0).first;

	ll from, to, color, length;
	string type;
	tuple<ll, ll, pair<ll, ll>> edge;
	pair<ll, ll> edge_info;
	REPI(v, euler_tour)	{
		tie(edge, type) = v;
		tie(from, to, edge_info) = edge;
		tie(color, length) = edge_info;
		if (type == "+") lengths[to] = lengths[from] + length;
		else lengths[from] = lengths[to] - length;
	}

	vector<ll> results(Q);
	vector<vector<tuple<ll, ll, ll, ll>>> node_to_color_length_index(N);
    REPD(i, 0, Q) {
		cin >> x >> y >> u >> v;
		--u, --v;
		ll a = lca.calculate(u, v);
		results[i] = lengths[u] + lengths[v] - lengths[a] * 2LL;

		node_to_color_length_index[u].emplace_back(x, y, i, 1);
		node_to_color_length_index[v].emplace_back(x, y, i, 1);
		node_to_color_length_index[a].emplace_back(x, y, i, -2);
	}

	vector<ll> count_by_color(N);
	vector<ll> length_sum_by_color(N);
	REPI(v, euler_tour)	{
		tie(edge, type) = v;
		tie(from, to, edge_info) = edge;
		tie(color, length) = edge_info;
		if (type == "+") {
			count_by_color[color] += 1LL;
			length_sum_by_color[color] += length;
		}
		else {
			count_by_color[color] -= 1LL;
			length_sum_by_color[color] -= length;
		}

		if (type == "+") {
			ll qindex, coef;
			REPI (info, node_to_color_length_index[to]) {
				tie(x, y, qindex, coef) = info;
				results[qindex] += (count_by_color[x] * y - length_sum_by_color[x]) * coef;
			}
		}
	}

	REPD(i, 0, Q) {
		cout << results[i] << endl;
	}

	return 0;
}

//main function
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);

	solve();
	// ll t;
	// cin >> t;
	// REPD(i, 0, t) solve();

	return 0;
}


Measured memory_bytes: 79792