#include <cmath>
#include <iostream>
#include <stack>
#include <vector>

template <class T, class Comp = std::less<T>>
struct bst;
template <class T, class Comp = std::less<T>>
bst<T, Comp>* build(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r);
template <class T, class Comp>
constexpr const bst<T, Comp>* find(const bst<T, Comp>* t, const T& v) noexcept;
template <class T, class Comp = std::less<T>>
bst<T, Comp>* construct_tree(const std::vector<T>& list);
template <class T, class Comp>
bst<T, Comp>* construct_tree(const std::vector<T>& list, int l, int r);
template <class T, class Comp = std::less<T>>
bst<T, Comp>* add(const bst<T, Comp>* t, const T& v);

template <class T, class Comp>
constexpr int my_comp(const T& a, const T& b) noexcept
{
	Comp c;
	return c(a, b) ? -1 : c(b, a) ? 1 : 0;
}

template <class T, class Comp>
struct bst
{
	const bst* l = nullptr;
	const bst* r = nullptr;
	const T v;

private:
	constexpr bst(const bst* l, const T& v, const bst* r) noexcept : l(l), r(r), v(v) {}
	friend bst<T, Comp>* build<T, Comp>(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r);
};

template <class T, class Comp>
bst<T, Comp>* build(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r)
{
	return new bst<T, Comp>(l, v, r);
}
template <class T, class Comp>
constexpr const bst<T, Comp>* find(const bst<T, Comp>* t, const T& v) noexcept
{
	if (t == nullptr) return t;
	switch (my_comp<T, Comp>(t->v, v))
	{
		case 1:
			return find(t->l, v);
		case -1:
			return find(t->r, v);
		default:
			return t;
	}
}
template <class T, class Comp>
bst<T, Comp>* add(const bst<T, Comp>* t, const T& v)
{
	if (t == nullptr) return build<T, Comp>(nullptr, v, nullptr);
	switch (my_comp<T, Comp>(t->v, v))
	{
		case 1:
			return build(add(t->l, v), t->v, t->r);
		case 0:
			return build(t->l, v, t->r);
		default:
			return build(t->l, t->v, add(t->r, v));
	}
}
template <class T, class Comp>
bst<T, Comp>* construct_tree(const std::vector<T>& list)
{
	return construct_tree<T, Comp>(list, 0, list.size());
}
template <class T, class Comp>
bst<T, Comp>* construct_tree(const std::vector<T>& list, int l, int r)
{
	if (l >= r) return nullptr;
	auto n = (l + r) / 2;
	return build(construct_tree<T, Comp>(list, l, n), list[n], construct_tree<T, Comp>(list, n + 1, r));
}

template <class T, class Comp>
std::ostream& operator<<(std::ostream& os, const bst<T, Comp>* t)
{
	if (t == nullptr) return os << "Empty";
	if (t->l != nullptr) os << t->l << ", ";
	os << t->v;
	if (t->r != nullptr) os << ", " << t->r;
	return os;
}

struct edge
{
	int to, col, len;
	edge(int to, int col, int len) : to(to), col(col), len(len) {}
};

struct info_t
{
	int col, cnt, dist;
	info_t(int col, int cnt, int dist) : col(col), cnt(cnt), dist(dist) {}
};
constexpr bool operator<(const info_t& a, const info_t& b) noexcept { return a.col < b.col; }

struct solver
{
	using tree = bst<info_t>*;
	int N, log;
	std::vector<int> depth, depth2, dbl;
	std::vector<std::vector<edge>> g;
	std::vector<tree> info;
	static int get_log(int N) { return int(std::ceil(std::log2(N) + 1)); }
	solver(int N) : N(N), log(get_log(N)), depth(N, 0), depth2(N, 0), dbl(N * get_log(N)), g(N), info(N, nullptr)
	{
		for (int i = 0; i < N - 1; i++)
		{
			int u, v, c, l;
			std::cin >> u >> v >> c >> l;
			g[--u].emplace_back(--v, --c, l);
			g[v].emplace_back(u, c, l);
		}
		auto s = std::stack<std::pair<int, int>>();
		s.emplace(-1, 0);
		std::vector<info_t> initial_value(N - 1, {0, 0, 0});
		for (int i = 0; i < N - 1; i++) initial_value[i].col = i;
		info[0] = construct_tree(initial_value);
		while (!s.empty())
		{
			auto tup = s.top();
			int p = tup.first, v = tup.second;
			s.pop();
			dbl[v] = p;
			for (auto& e : g[v])
				if (e.to != p)
					s.emplace(v, e.to);
				else if (p >= 0)
				{
					auto t = find(info[p], info_t(e.col, 0, 0))->v;
					info[v] = add(info[p], info_t(e.col, t.cnt + 1, t.dist + e.len));
					depth[v] = depth[p] + e.len;
					depth2[v] = depth2[p] + 1;
				}
		}
		for (int l = 1; l < log; l++)
			for (int i = 0; i < N; i++) dbl[l * N + i] = dbl[(l - 1) * N + i] < 0 ? -1 : dbl[(l - 1) * N + dbl[(l - 1) * N + i]];
	}
	void solve(int Q) const
	{
		for (int i = 0; i < Q; i++)
		{
			int c, d, u, v;
			std::cin >> c >> d >> u >> v;
			std::cout << calc(c - 1, d, u - 1, v - 1) << "\n";
		}
	}
	int calc(int c, int d, int u, int v) const
	{
		int p = lca(u, v);
		auto iu = find(info[u], info_t(c, 0, 0))->v;
		auto iv = find(info[v], info_t(c, 0, 0))->v;
		auto ip = find(info[p], info_t(c, 0, 0))->v;
		int cnt = iu.cnt + iv.cnt - 2 * ip.cnt;
		int len = iu.dist + iv.dist - 2 * ip.dist;
		return depth[u] + depth[v] - 2 * depth[p] - len + cnt * d;
	}
	int lca(int u, int v) const
	{
		if (depth2[u] > depth2[v]) return lca(v, u);
		for (int l = 0; l < log; l++)
			if ((depth2[v] - depth2[u]) & (1ul << l)) v = dbl[l * N + v];
		if (u == v) return u;
		for (int l = log - 1; l >= 0; l--)
			if (dbl[l * N + u] != dbl[l * N + v])
			{
				u = dbl[l * N + u];
				v = dbl[l * N + v];
			}
		return dbl[u];
	}
};

int main()
{
	std::cin.tie(0);
	std::ios::sync_with_stdio(false);
	int N, Q;
	std::cin >> N >> Q;
	solver(N).solve(Q);
	std::cout << std::flush;
	return 0;
}


Measured memory_bytes: 96308