#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

#ifndef bhartiya
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
// #pragma GCC target
// ("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#endif

#define int long long
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef gp_hash_table<int, int> umap;
typedef tree<int, null_type, less<int>, rb_tree_tag,
             tree_order_statistics_node_update>
    oset;
// not that imp
typedef pair<pii, int> piii;
typedef vector<int> vi;
typedef vector<pii> vii;

#define inf 200000000000000
#define mod 1000000007
#define eps 1e-7
#define PI 3.1415926535897932385
// #define PI acos(-1)

#define pb push_back
#define bitc __builtin_popcountll
#define mp make_pair
#define ff first
#define ss second
#define all(ar) ar.begin(), ar.end()
#define sz(x) (int)(x).size()

#define fr(i, a, b) for (int i = (a), _b = (b); i <= _b; i++)
#define rep(i, n) for (int i = 0, _n = (n); i < _n; i++)
#define repr(i, n) for (int i = n - 1; i >= 0; i--)
#define frr(i, a, b) for (int i = (a), _b = (b); i >= _b; i--)
#define foreach(it, ar) for (auto it = ar.begin(); it != ar.end(); it++)
#define fil(ar, val) memset(ar, val, sizeof(ar))  // 0x7f for inf

// clang-format off
#ifdef bhartiya
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
	cout << name << " : " << arg1 << endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
	const char* comma = strchr(names + 1, ',');cout.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
int begtime = clock();
#define end_routine() cout << "\n\nTime elapsed: " << (clock() - begtime)*1000/CLOCKS_PER_SEC << " ms\n\n";
#else
#define endl '\n'
#define trace(...)
#define end_routine()
#endif

mt19937 rng32(chrono::steady_clock::now().time_since_epoch().count());
inline bool equals(double a, double b) { return fabs(a - b) < 1e-9; }
ll modpow(ll b, ll e) {
	ll ans=1; for(;e;b=b*b%mod,e/=2) if(e&1) ans=ans*b%mod; return ans;}
// clang-format on

const int maxn = 200005;
struct query {
    int color, weight, u, v, index;
    // bool operator<(query z) { return color < z.color; }
    query(int a, int b, int c, int d, int e)
        : color(a), weight(b), u(c), v(d), index(e) {}
};

vector<query> queries[maxn];
vector<pair<pii, int>> edges[maxn];
vector<int> ans(maxn), tin(maxn), tout(maxn), depth(maxn), parent(maxn),
    par_w(maxn), par_c(maxn);
vector<pair<pii, int>> adj[maxn];  // for count and edges of a particular color
int dp[20][maxn], w_s[20][maxn];
int tim = 0, n, q;

void dfs(int s, int p) {
    tin[s] = tim++;
    for (auto edge : adj[s]) {
        int ch = edge.ff.ff, w = edge.ff.ss, col = edge.ss;
        if (ch == p) continue;
        dp[0][ch] = parent[ch] = s;
        // trace(ch, dp[0][ch]);
        par_c[ch] = col;
        w_s[0][ch] = par_w[ch] = w;
        depth[ch] = depth[s] + 1;
        dfs(ch, s);
    }
    tout[s] = tim++;
}

bool is_anc(int u, int v) {
    if (tin[v] >= tin[u] && tout[v] <= tout[u]) return true;
    return false;
}

void build_lca() {
    for (int i = 1; i < 20; i++) {
        rep(j, n) {
            dp[i][j] = dp[i - 1][dp[i - 1][j]];
            w_s[i][j] = w_s[i - 1][j] + w_s[i - 1][dp[i - 1][j]];
        }
    }
}

int find_sum(int u, int v) {
    int sum = 0;
    for (int i = 19; i >= 0; i--) {
        if (!is_anc(dp[i][u], v)) {
            sum += w_s[i][u];
            u = dp[i][u];
        }
        if (!is_anc(dp[i][v], u)) {
            sum += w_s[i][v];
            v = dp[i][v];
        }
    }
    if (!is_anc(u, v)) {
        sum += w_s[0][u];
        u = dp[0][u];
    }
    if (!is_anc(v, u)) {
        sum += w_s[0][v];
        v = dp[0][v];
    }
    assert(u == v);
    return sum;
}

void query_small(int col) {
    // trace(col, sz(queries[col]));
    for (auto quer : queries[col]) {
        int u = quer.u, v = quer.v, w = quer.weight, cnt = 0, sum = 0;
        for (auto edge : edges[col]) {
            int to = edge.ff.ff, from = edge.ff.ss, we = edge.ss;
            if (depth[to] < depth[from]) swap(to, from);
            // trace(to, from, we, depth[to], depth[from]);
            if (is_anc(to, u) ^ is_anc(to, v)) {
                if (is_anc(from, u) || is_anc(from, v)) {
                    cnt++;
                    sum += we;
                }
            }
        }
        // trace(w, cnt, sum, u, v);
        ans[quer.index] += (cnt * w - sum);
    }
}

int cnt[20][maxn], w_sum[20][maxn];

void query_big(int col) {
    for (int i = 0; i < n; i++) {
        if (par_c[i] == col)
            cnt[0][i] = 1, w_sum[0][i] = par_w[i];
        else
            cnt[0][i] = 0, w_sum[0][i] = 0;
    }
    for (int i = 1; i < 20; i++) {
        rep(j, n) {
            cnt[i][j] = cnt[i - 1][j] + cnt[i - 1][dp[i - 1][j]];
            w_sum[i][j] = w_sum[i - 1][j] + w_sum[i - 1][dp[i - 1][j]];
        }
    }
    for (auto quer : queries[col]) {
        int u = quer.u, v = quer.v, w = quer.weight;
        // trace(u,v);
        int cn = 0, we = 0;
        for (int i = 19; i >= 0; i--) {
            if (!is_anc(dp[i][u], v)) {
                we += w_sum[i][u];
                cn += cnt[i][u];
                u = dp[i][u];
            }
            if (!is_anc(dp[i][v], u)) {
                we += w_sum[i][v];
                cn += cnt[i][v];
                v = dp[i][v];
            }
        }
        // trace(u, v, col, dp[0][u], dp[0][v], cn, we);
        if (!is_anc(u, v)) {
            cn += cnt[0][u];
            we += w_sum[0][u];
            u = dp[0][u];
        }
        if (!is_anc(v, u)) {
            cn += cnt[0][v];
            we += w_sum[0][v];
            v = dp[0][v];
        }
        // trace(u, v, col, dp[0][u], dp[0][v], cn, we);
        assert(u == v);
        // we += w_sum[0][u] + w_sum[0][v];
        // cn += cnt[0][u] + cnt[0][v];
        ans[quer.index] += (cn * w - we);
    }
}

void solve() {
    cin >> n >> q;
    rep(i, n - 1) {
        int u, v, c, w;
        cin >> u >> v >> c >> w;
        u--;
        v--;
        adj[u].pb({{v, w}, c});
        adj[v].pb({{u, w}, c});
        edges[c].pb({{u, v}, w});
    }
    dfs(0, -1);
    build_lca();
    rep(i, q) {
        int col, w, u, v;
        cin >> col >> w >> u >> v;
        u--;
        v--;
        queries[col].pb(query(col, w, u, v, i));
        ans[i] += find_sum(u, v);
        // trace(u, v, ans[i]);
    }
    fr(i, 1, n - 1) {
        // trace(i, sz(edges[i]));
        if (sz(edges[i]) * sz(edges[i]) <= n)
            query_small(i);
        else
            query_big(i);
    }

    rep(i, q) { cout << ans[i] << endl; }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(10);  // cout<<fixed;
    cin.exceptions(cin.failbit);
#ifdef bhartiya
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    solve();
    end_routine();
}

Measured memory_bytes: 170412