#include <bits/stdc++.h>

struct Edge {
	int to;
	int64_t dist{1};

	int color;
};

using EdgeVec = std::vector<Edge>;
using EdgeLists = std::vector<EdgeVec>;


///////////////////////
// 最近共通祖先クエリ //
//////////////////////

// コンストラクタに渡す木は子に向かう有向グラフでも無向グラフでもいい
class LCA {
private:
	using ve = std::vector<Edge>;
	using vve = std::vector<ve>;
	using vi = std::vector<int>;
	using vvi = std::vector<vi>;

	const vve& edges_;
	vvi ancestors_;
	vi depthList_;
	const int root_;

	void initDFS(const int index, const int parent, const int depth)
	{
		ancestors_[index].front() = parent;
		depthList_[index] = depth;
		for (auto& e: edges_[index])
			if (e.to != parent)
				initDFS(e.to, index, depth + 1);
	}
	
public:
	const vi& depthList;

	LCA(const vve& adjacentList, const int root)
		: edges_(adjacentList), root_(root), depthList(depthList_)
	{
		int size{1};
		while (1 << (size - 1) <= (int)edges_.size()) size++;
		ancestors_.resize(edges_.size(), vi(size));
		depthList_.resize(edges_.size());
		initDFS(root_, root_, 0);
		for (int i{1}; i < size; i++)
			for (auto& e: ancestors_)
				e[i] = ancestors_[e[i - 1]][i - 1];
	}

	int calcAncestor(const int from, const int distance)
	{
		int ret{from};
		for (int digit{}, rest{distance}; rest > 0; rest >>= 1, digit++)
			if (rest & 1)
				ret = ancestors_[ret][digit];
		return ret;
	}

	int calcLCA(int index0, int index1)
	{
		if (depthList_[index0] > depthList_[index1])
			index0 = calcAncestor(index0, depthList_[index0] - depthList_[index1]);
		else
			index1 = calcAncestor(index1, depthList_[index1] - depthList_[index0]);
		if (index0 == index1) return index0;
		
		for (int digit{(int)ancestors_.front().size() - 1}; digit >= 0; digit--)
			if (ancestors_[index0][digit] != ancestors_[index1][digit])
			{
				index0 = ancestors_[index0][digit];
				index1 = ancestors_[index1][digit];
			}
		return ancestors_[index0][0];
	}
};

using vi3 = std::vector<std::array<int64_t, 3>>;
using vvi3 = std::vector<vi3>;
using vi = std::vector<int>;

EdgeLists edges;
vvi3 colorTable;
vi3 eulerTour;
vi tourTable;

void dfs(int, int64_t, int);
int bin_search(int, int, int64_t);

int main()
{
	int N, Q;
	scanf("%d%d", &N, &Q);
	edges.resize(N);
	for (int i{}; i < N - 1; i++)
	{
		int a, b, c, d;
		scanf("%d%d%d%d", &a, &b, &c, &d);
		a--; b--; c--;
		edges[a].push_back({b, d, c});
		edges[b].push_back({a, d, c});
	}
	LCA lca(edges, 0);

	colorTable.resize(N - 1, vi3(1));
	tourTable.resize(N, -1);
	dfs(0, 0, -1);
	
	for (int q_i{}; q_i < Q; q_i++)
	{
		int x, y, u, v;
		scanf("%d%d%d%d", &x, &y, &u, &v);
		x--; u--; v--;
		int ancestor{lca.calcLCA(u, v)};
		int64_t ans{eulerTour[tourTable[u]][1] + eulerTour[tourTable[v]][1] - 2 * eulerTour[tourTable[ancestor]][1]};
		ans += bin_search(u, x, y) + bin_search(v, x, y) - 2 * bin_search(ancestor, x, y);
		printf("%lld\n", ans);
	}

	return 0;
}

void dfs(int index, int64_t dist, int color)
{
	tourTable[index] = (int)eulerTour.size();
	eulerTour.push_back({index, dist, 0});
	for (auto& e: edges[index])
	{
		if (tourTable[e.to] >= 0) continue;
		auto& table{colorTable[e.color]};
		table.push_back({eulerTour.size(), table.back()[1] + e.dist, table.back()[2] + 1});
		dfs(e.to, dist + e.dist, e.color);
		table.push_back({eulerTour.size(), table.back()[1] - e.dist, table.back()[2] - 1});
		eulerTour.push_back({index, dist, 0});
	}
}

int bin_search(int index, int color, int64_t new_dist)
{
	int tour_i{tourTable[index]};
	auto& table{colorTable[color]};
	int ng{(int)table.size()}, ok{0};
	while (ng - ok > 1)
	{
		int mid{(ok + ng) >> 1};
		if (table[mid][0] <= tour_i) ok = mid;
		else ng = mid;
	}
	return table[ok][2] * new_dist - table[ok][1];
}

Measured memory_bytes: 45208