// #include <bits/stdc++.h>
#include <algorithm>
#include <array>
#include <bitset>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdio>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
typedef long long ll;
constexpr ll MOD = 1000000007;

template <class T, class Comp = std::less<T>>
struct bst;
template <class T, class Comp>
constexpr int count(const bst<T, Comp>* t) noexcept;
template <class T, class Comp>
constexpr int height(const bst<T, Comp>* t) noexcept;
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>
bst<T, Comp>* join(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r);
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;
	const int c = 1;
	const int h = 1;

private:
	constexpr bst(const bst* l, const T& v, const bst* r, int c) noexcept : l(l), r(r), v(v), c(c), h(1 + std::max(height(l), height(r))) {}
	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>
constexpr int count(const bst<T, Comp>* t) noexcept
{
	return t == nullptr ? 0 : t->c;
}
template <class T, class Comp>
constexpr int height(const bst<T, Comp>* t) noexcept
{
	return t == nullptr ? 0 : t->h;
}

template <class T, class Comp>
bst<T, Comp>* build(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r)
{
	int c = 1 + count(l) + count(r);
	int lh = height(l), rh = height(r);
	if (lh > rh + 1)
	{
		if (height(l->l) >= height(l->r)) return new bst<T, Comp>(l->l, l->v, build(l->r, v, r), c);
		return new bst<T, Comp>(build(l->l, l->v, l->r->l), l->r->v, build(l->r->r, v, r), c);
	}
	if (rh > lh + 1)
	{
		if (height(r->r) >= height(r->l)) return new bst<T, Comp>(build(l, v, r->l), r->v, r->r, c);
		return new bst<T, Comp>(build(l, v, r->l->l), r->l->v, build(r->l->r, r->v, r->r), c);
	}
	return new bst<T, Comp>(l, v, r, c);
}
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>* join(const bst<T, Comp>* l, const T& v, const bst<T, Comp>* r)
{
	int lh = height(l), rh = height(r);
	if (abs(lh - rh) <= 1) return build(l, v, r);
	return lh > rh ? build(l->l, l->v, join(l->r, v, r)) : build(join(l, v, r->l), r->v, r->r);
}
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 join(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;
			cin >> u >> v >> c >> l;
			g[--u].emplace_back(--v, --c, l);
			g[v].emplace_back(u, c, l);
		}
		auto s = std::queue<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.front();
			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)
	{
		for (int i = 0; i < Q; i++)
		{
			int c, d, u, v;
			cin >> c >> d >> u >> v;
			std::cout << calc(c - 1, d, u - 1, v - 1) << std::endl;
		}
		// for (int u = 0; u < N; u++)
		// 	for (int v = u + 1; v < N; v++)
		// 		for (int c = 0; c < N - 1; c++)
		// 			std::cout << "c = " << c << ", u = " << u << ", v = " << v << ": " << calc(c, 100, u, v) << std::endl;
	}
	int calc(int c, int d, int u, int v)
	{
		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)
	{
		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()
{
	// cin.tie(0);
	// ios::sync_with_stdio(false);
	int N, Q;
	cin >> N >> Q;
	solver(N).solve(Q);
	cout << flush;
	return 0;
}


Measured memory_bytes: 96308