#include "bits/stdc++.h"

#define REP(i,x,y) for(int i=(x);i<(y);i++)
#define RREP(i,x,y) for(int i=(y)-1;i>=(x);i--)
#define all(x) (x).begin(),(x).end()
// #define int long long

using namespace std;

// conversion
inline int toInt(string s) {int v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) {ostringstream sout;sout<<x;return sout.str();}

#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define dump(x)  cerr << #x << " = " << (x) << endl
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl
#else
#define eprintf(...) 42
#define dump(x) 42
#define debug(x) 42
#endif

typedef long long ll;

const ll MOD = 1e9 + 7;

struct Query {
    Query() {}
    Query(int color, int distance) : color(color), distance(distance) {}
    int color;
    int distance;
};

struct NodeInformation {
    int height;
    vector<int> parents; // parents[i] = parent node whose distance from current node is 2^i
    unordered_map<int, Query> queries; // <query, Query>
    unordered_map<int, int> distances; // <query, distanceToRoot>
};

// calculate nodes' height and parents
void dfs(int number, int previousNumber, int height, vector<int>& parents, vector<unordered_map<int, pair<int, int>>>& edges, vector<NodeInformation>& info) {
    REP(i,0,height) {
        const int distance = pow(2,i);
        const int index = parents.size() - distance;
        if (index < 0) break;

        info[number].parents.push_back(parents[index]);
    }
    parents.push_back(number);

    info[number].height = height;

    for(const auto child : edges[number]) {
        if (child.first == previousNumber) continue;

        dfs(child.first, number, height+1, parents, edges, info);
    }

    parents.pop_back();
}

// calculate nodes' distance
void dfs(int number, int previousNumber, int distance, unordered_map<int, pair<int, int>>& sumByColor, vector<unordered_map<int, pair<int, int>>>& edges, vector<NodeInformation>& info) {
    for (const auto q : info[number].queries) {
        const int queryNumber = q.first;
        const Query query = q.second;
        info[number].distances[queryNumber] = distance - sumByColor[query.color].second + sumByColor[query.color].first * query.distance;
    }
    for (const auto child : edges[number]) {
        if (child.first == previousNumber) continue;

        const int nextDistance = child.second.second;
        const int nextColor = child.second.first;

        sumByColor[nextColor].first++;
        sumByColor[nextColor].second += nextDistance;

        dfs(child.first, number, distance + nextDistance, sumByColor, edges, info);

        sumByColor[nextColor].first--;
        sumByColor[nextColor].second -= nextDistance;
    }
}

int searchParent(int number, int distanceToParent, vector<NodeInformation>& info) {
    if (distanceToParent == 0) return number;

    int i = log2(distanceToParent); // 2^i
    if (distanceToParent == pow(2,i)) return info[number].parents[i];
    return searchParent(info[number].parents[i], distanceToParent - pow(2,i), info);
}

int searchNearestCommonParent(int u, int v, vector<NodeInformation>& info) {
    if (info[u].height > info[v].height) swap(u, v);
    v = searchParent(v, info[v].height - info[u].height, info); // move v to the node whose height is same as u
    if (u == v) return u;
    while (info[u].parents.size() > 1) {
        if (info[u].parents[0] == info[v].parents[0]) return info[u].parents[0];
        RREP(i,0,info[u].parents.size()) {
            if (info[u].parents[i] != info[v].parents[i]) {
                u = info[u].parents[i];
                v = info[v].parents[i];
                break;
            }
        }
    }
    if (u == v) return u;
    if (info[u].parents.size() == 1 && info[u].parents[0] == info[v].parents[0]) return info[u].parents[0];
    assert(false);
}

int getDistance(int u, int v, int query, vector<NodeInformation>& info) {
    const int commonParent = searchNearestCommonParent(u, v, info);

    return info[u].distances[query] + info[v].distances[query] - 2 * info[commonParent].distances[query];
}

void solve(int N, int Q, vector<int>& a, vector<int>& b, vector<int>& c, vector<int>& d, vector<int>& x, vector<int>& y, vector<int>& u, vector<int>& v) {
    vector<NodeInformation> info(N+1);
    vector<unordered_map<int, pair<int, int>>> edges(N+1);

    REP(i,1,N) {
        edges[a[i]][b[i]] = {c[i], d[i]};
        edges[b[i]][a[i]] = {c[i], d[i]};
    }

    vector<int> parents;
    dfs(1, 0, 0, parents, edges, info);

    // input queries to nodes
    REP(i,0,Q) {
        info[u[i]].queries[i] = Query(x[i], y[i]);
        info[v[i]].queries[i] = Query(x[i], y[i]);
        info[searchNearestCommonParent(u[i], v[i], info)].queries[i] = Query(x[i], y[i]);
    }

    unordered_map<int, pair<int, int>> sumByColor;
    dfs(1, 0, 0, sumByColor, edges, info);

    stringstream ss;
    REP(i,0,Q) {
        int answer = getDistance(u[i], v[i], i, info);
        ss << answer << '\n';
    }
    cout << ss.str();

    return;
}

signed main() {
    int N, Q;
    cin >> N >> Q;
    
    vector<int> a(N), b(N), c(N), d(N);
    REP(i,1,N) cin >> a[i] >> b[i] >> c[i] >> d[i];

    vector<int> x(Q), y(Q), u(Q), v(Q);
    REP(i,0,Q) cin >> x[i] >> y[i] >> u[i] >> v[i];

    solve(N, Q, a, b, c, d, x, y, u, v);

    return 0;
}


Measured memory_bytes: 80912