#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp> // Common file 
#include <ext/pb_ds/tree_policy.hpp> 
#include <functional> // for less 
#define pb push_back
#define For(i,s,e) for (ll i=(s); i<(e); i++)
#define Debug_array(a,n) for (ll i=(0); i<(n); i++) cout<<a[i]<<" "
#define Foe(i,s,e) for (ll i=(s); i<=(e); i++)
#define Fod(i,s,e) for (ll i=(s)-1; i>=(e); i--)
#define pii pair<ll,ll>
#define fi first
#define se second
#define endl "\n"
#define mp make_pair
#define big_prime 15486277
#define bigger_prime 179424697
#define biggest_prime 32416188691
//#define random_shuffle(indices.begin(), indices.end());
//std::random_device rd;
//std::mt19937 g(rd());
//std::shuffle(v.begin(), v.end(), g);
using namespace __gnu_pbds; 
using namespace std;
template <class T> ostream& operator << (ostream &os, const vector<T> &v) { for (T i : v) os << i << ' '; return os; }
template <class T> ostream& operator << (ostream &os, const set<T> &v) { for (T i : v) os << i << ' '; return os; }
template <class T, class S> ostream& operator << (ostream &os, const pair<T, S> &v) { os << v.first << ' ' << v.second; return os; }
// template <class T, class S> ostream& operator << (ostream &os, const unordered_map<T, S> &v) { for (auto i : v) os << '(' << i.first << "=>" << i.second << ')' << ' '; return os; }
 
#ifndef ONLINE_JUDGE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
    template <class Arg1> void __f(const char* name, Arg1&& arg1) { cerr << name << " : " << arg1 << endl; }
    template <class Arg1, class... Args>
    void __f(const char* names, Arg1&& arg1, Args&&... args) {
        const char* sep = strchr(names + 1, ',');
        cerr.write(names, sep - names) << " : " << arg1 << "  ";
        __f(sep + 1, args...);
    }
#else
#define trace(...) 0
#define _CRT_SECURE_NO_WARNINGS
#endif // ifndef ONLINE_JUDGE


typedef long long ll;
typedef tree<ll, null_type, less<ll>, rb_tree_tag,tree_order_statistics_node_update> ordered_set; 

#define Mod 1000000007
#define MAX 100100

struct Node
{
	ll x,color,dist;
	Node(ll x,ll color,ll dist) : x(x) , color(color) , dist(dist) {};
};
struct Query
{
	ll color,dist,u,v,index,ans;
	bool minus;
	Query(ll color,ll dist,ll u,ll v,ll index) : color(color) , dist(dist) , u(u) , v(v) , index(index) {};
};

ll n,Q;
vector<Node> adj[MAX];
vector<Query> queries;
vector<Query> q[MAX];
vector<vector<ll> > adj2;

pii colors[MAX]; //{count,length}


void dfs(ll start,ll parent,ll dist){

	For(i,0,q[start].size()){
		Query& t = q[start][i];
		t.ans += (colors[t.color].fi*t.dist);
		t.ans -= (colors[t.color].se);
		t.ans += dist;
	}

	for(Node x:adj[start]) if(x.x!=parent){
		colors[x.color].fi++;
		colors[x.color].se+=x.dist;

		dfs(x.x,start,dist+x.dist);

		colors[x.color].fi--;
		colors[x.color].se-=x.dist;
	}
	return;
}

struct LCA {
    vector<ll> height, euler, first, segtree;
    vector<bool> visited;
    ll n;

    //0 indexed
    LCA(vector<vector<ll>> &adj, ll root = 0) {
        n = adj.size();
        height.resize(n);
        first.resize(n);
        euler.reserve(n * 2);
        visited.assign(n, false);
        dfs(adj, root);
        ll m = euler.size();
        segtree.resize(m * 4);
        build(1, 0, m - 1);
    }

    void dfs(vector<vector<ll>> &adj, ll node, ll h = 0) {
        visited[node] = true;
        height[node] = h;
        first[node] = euler.size();
        euler.push_back(node);
        for (auto to : adj[node]) {
            if (!visited[to]) {
                dfs(adj, to, h + 1);
                euler.push_back(node);
            }
        }
    }

    void build(ll node, ll b, ll e) {
        if (b == e) {
            segtree[node] = euler[b];
        } else {
            ll mid = (b + e) / 2;
            build(node << 1, b, mid);
            build(node << 1 | 1, mid + 1, e);
            ll l = segtree[node << 1], r = segtree[node << 1 | 1];
            segtree[node] = (height[l] < height[r]) ? l : r;
        }
    }

    ll query(ll node, ll b, ll e, ll L, ll R) {
        if (b > R || e < L)
            return -1;
        if (b >= L && e <= R)
            return segtree[node];
        ll mid = (b + e) >> 1;

        ll left = query(node << 1, b, mid, L, R);
        ll right = query(node << 1 | 1, mid + 1, e, L, R);
        if (left == -1) return right;
        if (right == -1) return left;
        return height[left] < height[right] ? left : right;
    }

    //LCA is O(logN)
    ll lca(ll u, ll v) {
        ll left = first[u], right = first[v];
        if (left > right)
            swap(left, right);
        return query(1, 0, euler.size() - 1, left, right);
    }
};


int main(){
	ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
	For(i,0,MAX) colors[i] = {0,0};

	cin>>n>>Q;
	adj2.resize(n);
	For(i,0,n-1){
		ll x,y;cin>>x>>y;x--;y--;
		ll c,d;cin>>c>>d;c--;
		adj[x].pb(Node(y,c,d));
		adj[y].pb(Node(x,c,d));

		adj2[x].pb(y);
		adj2[y].pb(x);
	}

	LCA L(adj2);

	For(i,0,Q){
		ll color,dist,u,v;
		cin>>color>>dist>>u>>v;
		color--;u--;v--;
		queries.pb(Query(color,dist,u,v,i));

		queries.back().ans = 0;
		queries.back().minus = 0;

		q[u].pb(queries.back());
		q[v].pb(queries.back());

		queries.back().minus=1;
		q[L.lca(u,v)].pb(queries.back());
	}	

	dfs(0,-1,0);

	ll ans[Q];
	memset(ans,0,sizeof(ans));
	For(i,0,n){
		for(Query t:q[i]){
			if(!t.minus)
				ans[t.index]+=t.ans;
			else
				ans[t.index]-=(2*t.ans);
		}
	}
	For(i,0,Q){
		cout<<ans[i]<<endl;
	}































	
}

Measured memory_bytes: 63692