#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

struct Edge{
	Edge(int arg_to,int arg_color,ll arg_dist){
		to = arg_to;
		color = arg_color;
		dist = arg_dist;
	}
	int to,color;
	ll dist;
};

struct Query{

	int color,u,v;
	ll next_dist;
};

struct Info{
	Info(int arg_query_id, ll arg_mult){
		query_id = arg_query_id;
		mult = arg_mult;
	}
	int query_id;
	ll mult;
};


vector<Edge> G[SIZE]; //グラフの隣接リスト表現
int N; //ノードの個数
int root; //根ノードの番号
int MAX_LOG_V = 17;
int POW[18];

int parent[18][SIZE];
ll depth[SIZE];
ll DIST[SIZE],SUM[SIZE],COUNT[SIZE];
Query query[SIZE];
ll ans[SIZE];
vector<Info> info[SIZE];


//parentとdepthを再帰的に設定
void dfs(int node_id,int parent_id,int d){
	parent[0][node_id] = parent_id;
	depth[node_id] = d;
	for(int i = 0; i < G[node_id].size(); i++){
		if(G[node_id][i].to != parent_id){
			DIST[G[node_id][i].to] = DIST[node_id]+G[node_id][i].dist;
			dfs(G[node_id][i].to,node_id,d+1);
		}
	}
}

//初期化
void init(){
	//parent[0]とdepthを初期化する
	dfs(root,-1,0);
	//parentを初期化する
	for(int k = 0; k + 1 < MAX_LOG_V; k++){
		for(int node_id = 0; node_id < N; node_id++){
			if(parent[k][node_id] < 0)parent[k+1][node_id] = -1; //node_idの2^k上のノードがルートノードより上なら、2^(k+1)上も同様とする
			else{
				parent[k+1][node_id] = parent[k][parent[k][node_id]];
			}
		}
	}
}

//leftとrightのLCAを求める
int lca(int left,int right){
	//leftとrightの深さが同じになるまで親を辿る
	if(depth[left] > depth[right])swap(left,right); //rightの方が深い所にいる

	for(int k = MAX_LOG_V-1; k >= 0; k--){
		if(depth[right]-depth[left] >= POW[k]){ //たとえば深さの差が39なら、32+4+2+1のように、ノードを上方に移動させる
			right = parent[k][right];
		}
	}

	if(left == right)return left;

	for(int k = MAX_LOG_V-1; k >= 0; k--){
		if(parent[k][left] == parent[k][right]){
			//Do nothing
		}else{
			left = parent[k][left];
			right = parent[k][right];
		}
	}
	return parent[0][left]; //最後は、leftの親とrightの親が必ず一致している
}

ll calc_dist(int u,int v){

	int LCA = lca(u,v);

	return DIST[u]+DIST[v]-2*DIST[LCA];
}

void recursive(int node_id,int pre){

	for(int i = 0; i < info[node_id].size(); i++){

		Query q = query[info[node_id][i].query_id];

		ll work = COUNT[q.color]*q.next_dist-SUM[q.color];

		ans[info[node_id][i].query_id] += info[node_id][i].mult*work;
	}

	for(int i = 0; i < G[node_id].size(); i++){

		int child = G[node_id][i].to;
		if(child == pre)continue;

		SUM[G[node_id][i].color] += G[node_id][i].dist;
		COUNT[G[node_id][i].color] += 1;
		recursive(child,node_id);

		SUM[G[node_id][i].color] -= G[node_id][i].dist;
		COUNT[G[node_id][i].color] -= 1;
	}
}

int main(){

	for(int i = 0; i <= 17; i++)POW[i] = pow(2,i);

	int num_query;
	scanf("%d %d",&N,&num_query);

	int from,to,color;
	ll dist;

	for(int i = 0; i < N-1; i++){

		scanf("%d %d %d %lld",&from,&to,&color,&dist);
		from--;
		to--;
		color--;

		G[from].push_back(Edge(to,color,dist));
		G[to].push_back(Edge(from,color,dist));
	}

	for(int i = 0; i < N; i++){

		DIST[i] = 0;
	}

	root = 0;
	init();

	for(int i = 0; i < num_query; i++){

		scanf("%d %lld %d %d",&query[i].color,&query[i].next_dist,&query[i].u,&query[i].v);
		query[i].color--;
		query[i].u--;
		query[i].v--;

		int LCA = lca(query[i].u,query[i].v);

		ans[i] = calc_dist(query[i].u,query[i].v); //デフォルトの距離

		info[query[i].u].push_back(Info(i,1));
		info[query[i].v].push_back(Info(i,1));
		info[LCA].push_back(Info(i,-2));
	}

	for(int i = 0; i < N; i++){

		SUM[i] = 0;
		COUNT[i] = 0;
	}

	recursive(root,-1);

	for(int i = 0; i < num_query; i++){

		printf("%lld\n",ans[i]);
	}

	return 0;
}


Measured memory_bytes: 36596