import std.stdio, std.array, std.string, std.conv, std.algorithm;
import std.typecons, std.range, std.random, std.math, std.container;
import std.numeric, std.bigint, core.bitop, std.bitmanip;

void main() {
    auto s = readln.split.map!(to!int);
    auto N = s[0];
    auto K = s[1];
    auto G = new Tuple!(int, int, long)[][](N);
    auto T = new LCA(N, 0);
    foreach (_; 0..N-1) {
        auto t = readln.split.map!(to!int);
        auto u = t[0] - 1;
        auto v = t[1] - 1;
        auto c = t[2] - 1;
        auto d = t[3].to!long;
        G[u] ~= tuple(v, c, d);
        G[v] ~= tuple(u, c, d);
        T.add_edge(u, v);
    }
    auto Q = new Tuple!(int, long, int, int, int)[](K);
    auto V = new int[][](N);
    foreach (i; 0..K) {
        auto t = readln.split.map!(to!int);
        auto c = t[0] - 1;
        auto d = t[1].to!long;
        auto u = t[2] - 1;
        auto v = t[3] - 1;
        auto lca = T.lca(u, v);
        Q[i] = tuple(c, d, u, v, lca);
        V[u] ~= i;
        V[v] ~= i;
        if (u != lca && v != lca) V[lca] ~= i;
    }

    long current_normal_dist = 0;
    auto current_colored_dist = new long[](N);
    auto current_colored_count = new long[](N);
    auto ans = new long[](K);

    void dfs(int n, int p) {
        foreach (qid; V[n]) {
            int color = Q[qid][0];
            long cost = Q[qid][1];
            if (Q[qid][2] == n || Q[qid][3] == n) {
                ans[qid] += current_normal_dist;
                ans[qid] -= current_colored_dist[color];
                ans[qid] += current_colored_count[color] * cost;
            }
            if (Q[qid][4] == n) {
                ans[qid] -= current_normal_dist * 2;
                ans[qid] += current_colored_dist[color] * 2;
                ans[qid] -= current_colored_count[color] * cost * 2;
            }
        }
        foreach (to; G[n]) {
            int m = to[0];
            int color = to[1];
            long cost = to[2];
            if (m == p) continue;
            current_normal_dist += cost;
            current_colored_dist[color] += cost;
            current_colored_count[color] += 1;
            dfs(m, n);
            current_normal_dist -= cost;
            current_colored_dist[color] -= cost;
            current_colored_count[color] -= 1;
        }
    }

    dfs(0, -1);
    ans.each!writeln;
}

class LCA {
    int n, root, lgn;
    int[][] g;
    int[] depth;
    int[][] dp;
    bool constructed = false;

    this(int n, int root) {
        this.n = n;
        this.root = root;
        lgn = bsr(n) + 3;
        g = new int[][](n);
        depth = new int[](n);
        dp = new int[][](n, lgn);
    }

    void add_edge(int u, int v) {
        g[u] ~= v;
        g[v] ~= u;
    }

    void construct() {
        auto stack = new Tuple!(int, int, int)[](n+10);
        int sp = 0;
        stack[0] = tuple(root, -1, 0);
        while (sp >= 0) {
            auto u = stack[sp][0];
            auto p = stack[sp][1];
            auto d = stack[sp][2];
            sp -= 1;
            dp[u][0] = p;
            depth[u] = d;
            foreach (v; g[u]) if (v != p) stack[++sp] = tuple(v, u, d+1);
        }

        foreach (k; 0..lgn-1)
            foreach (i; 0..n)
                dp[i][k+1] = (dp[i][k] == -1) ? -1 : dp[dp[i][k]][k];
        constructed = true;
    }

    void dfs(int u, int p, int d) {
        dp[u][0] = p;
        depth[u] = d;
        foreach (v; g[u]) if (v != p) dfs(v, u, d+1);
    }

    int lca(int a, int b) {
        if (!constructed) construct;
        if (depth[a] < depth[b]) swap(a, b);

        int diff = depth[a] - depth[b];
        foreach_reverse (i; 0..lgn) if (diff & (1<<i)) a = dp[a][i];

        if (a == b) return a;

        int K = lgn;
        while (dp[a][0] != dp[b][0]) {
            foreach_reverse (k; 0..lgn) {
                if (dp[a][k] != dp[b][k]) {
                    a = dp[a][k];
                    b = dp[b][k];
                    K = k;
                }
            }
        }

        return dp[a][0];
    }
}


Measured memory_bytes: 80124