#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <string>
#include <sstream>
#include <complex>
#include <vector>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <functional>

using namespace std;
 
#define mod 1000000007
#define FOR(x,to) for(int x=0;x<(to);x++)
#define FORR(x,arr) for(auto& x:arr)
#define ALL(a) (a.begin()),(a.end())
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
#define long long long
inline int rei(){int x;cin>>x;return x;}
inline long rel(){long x;cin>>x;return x;}
inline string res(){string x;cin>>x;return x;}
//------------------------------------------------------- 
template<class T>
struct SparseTable{
	vector<T> st[21];
	void Init(int N,vector<T> &data){
		st[0].resize(N);
		int h = 1;
		while ((1 << h) <= N){
			st[h].resize(N - (1 << h) + 1);
			h++;
		}
		for(int i=0;i<N;i++){
			st[0][i] = data[i];
		}
		for(int j=1;j<h;j++){
			for(int i=0;i<N-(1<<j)+1;i++){
				st[j][i] = min(st[j-1][i],st[j-1][i + (1 << (j - 1))]);
			}
		}
	}
	// 4 -> 2 3 -> 1
	inline int TopBit(int t){
		return 31-__builtin_clz(t);
	}
	T GetMin(int b,int e){
        e++;
		int diff = TopBit(e-b);
		return min(st[diff][b], st[diff][e - (1 << diff)]);
	}
};
struct LowestCommonAncestor{
    int N;
    vector<int> path, depth, in_order, out_order;
    std::vector<pair<int,int>> dat;
	SparseTable<pair<int,int>> table;

    LowestCommonAncestor(const vector<vector<int>> &G,int root=0)
        : N(G.size()),
          path(N * 2 - 1),
          depth(N * 2 - 1),
          in_order(N),
          out_order(N),
		  dat(N * 2 - 1) {
        int k = 0;
        dfs(G, root, -1, 0, k);
        for (int i = 0; i < depth.size(); ++i){
            dat[i] = make_pair(depth[i],i);
		}
		table.Init(dat.size(),dat);
    }

    int Query(int u,int v) {
        int l = min(in_order[u], in_order[v]);
        int r = max(in_order[u], in_order[v]);
        auto res = table.GetMin(l,r);
        return path[res.second];
    }

    void dfs(const vector<vector<int>> &G,int v,int f,int d,int &k) {
        in_order[v] = k;
        path[k] = v;
        depth[k++] = d;
        for (auto &e : G[v]){
            if (e != f) {
                dfs(G,e,v,d+1,k);
                path[k] = v;
                depth[k++] = d;
            }
        }
        out_order[v] = k-1;
    }
};
void dfs(int N,vector<tuple<int,long,int>> G[],function<void(int,int,long,int)> F){
	stack<pair<int,int>> sp;
	sp.push({0,-1});
	while(!sp.empty()){
		int v = sp.top().first;
		int f = sp.top().second;
		sp.pop();
		for(int i=0;i<G[v].size();i++){
			int t = get<0>(G[v][i]);
			if(t != f){
				F(t,v,get<1>(G[v][i]),get<2>(G[v][i]));
				sp.push({t,v});
			}
		}
	}
}
vector<tuple<int,long,int>> G[100000];
vector<tuple<int,int,long>> E[99999];
long CostC[250][100000];
int NumC[250][100000];
long Cost[100000];
int colortoind[100000];
void Calc(){
	int N = rei();
	int Q = rei();
	vector<vector<int>> GG(N,vector<int>());
	for(int i=0;i<N-1;i++){
		int a = rei()-1;
		int b = rei()-1;
		int c = rei()-1;
		int d = rei();
		E[c].push_back(make_tuple(a,b,d));
		G[a].push_back(make_tuple(b,d,c));
		G[b].push_back(make_tuple(a,d,c));
		GG[a].push_back(b);
		GG[b].push_back(a);
	}
	LowestCommonAncestor Lo(GG);
	int coi = 0;
	for(int i=0;i<N-1;i++){
		if(E[i].size() > 400){
			colortoind[i] = coi;
			coi++;
		}
		else{
			colortoind[i] = -1;
		}
	}
	function<void(int,int,long,int)> F = [&](int v,int f,long cost,int color){
		if(f == -1){
			return;
		}
		Cost[v] = Cost[f] + cost;
		for(int i=0;i<coi;i++){
			NumC[i][v] = NumC[i][f];
			CostC[i][v] = CostC[i][f];
		}
		if(colortoind[color] != -1){
			CostC[colortoind[color]][v] += cost;
			NumC[colortoind[color]][v]++;
		}
	};
	dfs(N,G,F);
	for(int i=0;i<Q;i++){
		int col = rei()-1;
		int d = rei();
		int u = rei()-1;
		int v = rei()-1;
		int uv = Lo.Query(u,v);
		long ans = Cost[u] + Cost[v] - 2 * Cost[uv];
		if(colortoind[col] != -1){
			ans -= CostC[colortoind[col]][u] + CostC[colortoind[col]][v] - 2 * CostC[colortoind[col]][uv];
			ans += d*(NumC[colortoind[col]][u] + NumC[colortoind[col]][v] - 2 * NumC[colortoind[col]][uv]);
		}
		else{
			for(tuple<int,int,long> e:E[col]){
				int a = get<0>(e);
				int b = get<1>(e);
				int ch = a+b - Lo.Query(a,b);
				if(Lo.Query(ch,u) == ch){
					ans += d - get<2>(e);
				}
				if(Lo.Query(ch,v) == ch){
					ans += d - get<2>(e);
				}
				if(Lo.Query(ch,uv) == ch){
					ans -= 2 * (d - get<2>(e));
				}
			}
		}
		cout << ans << "\n";
	}
}
int main(int argc,char** argv){
	ios::sync_with_stdio(false), cin.tie(0);
	cout.tie(0); Calc(); return 0;
}

Measured memory_bytes: 61036