#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/* LCA 木のノードの共通の祖先を求める */
struct LCA {
	vector<vector<pair<int,int>>> &v;
	vector<vector<int>> parent;
	vector<int> depth;
	const int n;
	const int root;
	
	using intfint = int (*)(int);
	
	int max_depth; // rootのdepthは0とする
	int level; // 2^[0..level-1] の祖先のテーブルを持つ。
	// max_depth == 0 -> level = 0
	// max_depth == 1 -> level = 1
	// max_depth == 2,3 -> level = 2
	// max_depth == 4,5,6,7 -> level = 3
	
	void dfs( int node, int parent_node, int d ){
		parent[0][node] = parent_node;
		depth[node] = d;
		max_depth = max( max_depth, d );
		
		for ( auto it : v[node] ){
			int next_node = it.first;
			if ( next_node != parent_node ){
				dfs( next_node, node, d+1 );
			}
		}
	}
	
	LCA(int n, int root, vector<vector<pair<int,int>>> &v ) : n(n), root(root), v(v) {
		depth.resize(n);
		parent.resize(1);
		parent[0].resize(n);
		max_depth = 0;
		dfs( root, -1, 0 );
		
		level = 0;
		while ( (1<<level) <= max_depth )
			level++;
		parent.resize(level);
		
		for ( int k = 1; k < level; k++ ){
			parent[k].assign(n,-1);
			for ( int i = 0; i < n; i++ ){
				if ( parent[k-1][i] != -1 )
					parent[k][i] = parent[k-1][parent[k-1][i]];
			}
		}
		
	}
	
	int query(int u, int v){
		if ( depth[u] > depth[v] )
			swap( u, v );
		int d = (depth[v]-depth[u]);
		
		for ( int i = 0; i < level; i++ )
			if ( d & (1<<i) )
				v = parent[i][v];
		
		if ( u == v )
			return u;
		
		for ( int i = level-1; i >= 0; i-- ){
			if ( parent[i][u] != parent[i][v] ){
				u = parent[i][u];
				v = parent[i][v];
			}
		}
		return parent[0][u];
	}
	
	void dump(){
		cout << "LCA parent\n";
		for ( int i = 0; i < n; i++ ){
			cout << i+1 << ":";
			for ( int j = 0; j < level; j++ )
				cout << parent[j][i]+1 << " ";
			cout << endl;
		}
	}
};



int N, Q;
vector<vector<pair<int,int>>> v;

struct edgeinfo {
	int l, r; // euler tour の L R 
	int c;
	int d;
	
	int same_color_eid;     // ルートに向かって直近の同じ色の辺
	int same_color_c_count; // この辺を含めて、ルートまでの間に同じ色の辺が何個あるか
	int same_color_d_sum;   // この辺を含めて、ルートまでの間の同じ色の辺のdの合計
	int node; // この辺の先にあるノード
};

edgeinfo edges[100001];
struct l_eid{
	int l;
	int eid;
};
map<int,vector<l_eid>> color_to_l_eid; // color -> vector{l, eid}

struct nodeinfo {
	int d_sum;
	int l, r;
};

vector<nodeinfo> nodes;


int euler_ct = 0; // euler tour counter
void dfs( int node, int parent_node, int d_sum, int depth ){
	nodeinfo &n = nodes[node];
	n.l = euler_ct++;
	n.d_sum = d_sum;
	
	for ( auto it : v[node] ){
		int next_node = it.first;
		int eid = it.second;
		edgeinfo &e = edges[eid];
		
		if ( next_node == parent_node )
			continue;
		
		auto &v = color_to_l_eid[e.c];
		int same_color_eid = ( v.size() != 0 ) ? v.back().eid : 0; //ルートに向かって直近の同じ色の辺
		e.same_color_eid      = same_color_eid;
		e.same_color_c_count  = edges[same_color_eid].same_color_c_count + 1;
		e.same_color_d_sum    = edges[same_color_eid].same_color_d_sum + e.d;
		e.node = next_node;
		
		e.l = euler_ct++;
		v.push_back({e.l,eid});
		
		dfs( next_node, node, d_sum+e.d, depth+1 );
		
		e.r = euler_ct++;
		v.push_back({e.r,same_color_eid});
	}
	n.r = euler_ct++;
}


/*
  色xの辺のコストがyになった場合、ルートからnode_idに移動するコストがいくらになるか計算する
*/
ll modcost( int node_id, int x, int y ){
	nodeinfo &n = nodes[node_id];
	int d_sum = n.d_sum;
	
	l_eid cmp = {n.l, 0};
	// node_id からルートに行くまでの間で最も近い色xの辺を探す
	const auto& p = lower_bound( color_to_l_eid[x].begin(), color_to_l_eid[x].end(), cmp, 
		[](const l_eid &l, const l_eid &r){return l.l < r.l;} );
	
	//cout << "node " << node_id+1 << " " << d_sum << endl;
	if ( p != color_to_l_eid[x].begin() ){
		edgeinfo &e = edges[(p-1)->eid];
		//cout << "  modify eid=" << (p-1)->eid << endl;
		d_sum -= e.same_color_d_sum;
		d_sum += e.same_color_c_count * y;
	}
	return d_sum;
}



int main(){
	cin >> N >> Q;
	v.resize(N);
	
	map<int,int> color_count;
	
	edges[0] = {-1,0,0,0,0,0,0,0};
	for ( int i = 1; i <= N-1; i++ ){
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		a--;
		b--;
		
		v[a].push_back({b,i});
		v[b].push_back({a,i});
		color_count[c]++;
		edges[i] = {0,0,c,d,0,0,0,0};
	}
	
	for ( auto it : color_count )
		color_to_l_eid[it.first].reserve(it.second*2);
	
	nodes.resize(N);
	
	dfs(0,-1,0,0);
	
	//for ( int i = 1; i < N; i++ ){
	//	edgeinfo &e = edges[i];
	//	cout << "edge " << i << " node" << e.node+1 << " l=" << e.l << " r=" << e.r << " c=" << e.c << " d=" << e.d << " same_e=" << e.same_color_eid << " ct=" << e.same_color_c_count << " dsum=" << e.same_color_d_sum << endl;
	//}
	
	LCA lca(N,0,v);
	
	for ( int i = 0; i < Q; i++ ){
		int x, y, u, v;
		cin >> x >> y >> u >> v;
		u--;
		v--;
		
		// lca: O(log(N))
		int l = lca.query( u, v );
		
		// modcost: O(log(N))
		int path_cost = modcost(u,x,y) + modcost(v,x,y) - modcost(l,x,y)*2;
		cout << path_cost << "\n";
	}
	
	
	return 0;
}



Measured memory_bytes: 35584