#include <iostream>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <fstream>
#include <bitset>
#include <queue>
#include <stack>
#include <deque>
#include <time.h>
#include <complex>

using std::cin;
using std::cout;
using std::cerr;
using std::endl;

using std::map;
using std::set;
using std::bitset;
using std::vector;
using std::string;
using std::multimap;
using std::multiset;
using std::deque;
using std::queue;
using std::stack;
using std::pair;
using std::iterator;
using std::complex;

using std::sort;
using std::stable_sort;
using std::reverse;
using std::max_element;
using std::min_element;
using std::unique;
using std::ios_base;
using std::swap;
using std::fill;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<long long> vl;
typedef string S;
typedef complex<double> cd;

inline ll max(ll a, ll b)
{
    if (a > b)
        return a;
    return b;
}

inline ll min(ll a, ll b)
{
    if (a < b)
        return a;
    return b;
}

namespace MySpace{
    struct Summ_Segment_Tree{
        vector<int> a;
        int l, r;

        private:
        int __summ(int L, int R, int l, int r, int v)
        {
            if (L <= l && r <= R)
                return a[v];
            if (R <= l || r <= L)
                return 0;
            int m = (l + r) / 2;
            return __summ(L, R, l, m, 2 * v + 1) + __summ(L, R, m, r, 2 * v + 2);
        }

        void __set(int P, int l, int r, int v, int V)
        {
            if (l + 1 == r)
            {
                a[v] = V;
                return;
            }
            int m = (l + r) / 2;
            if (P < m)
            {
                __set(P, l, m, 2 * v + 1, V);
                a[v] = a[2 * v + 1] + a[2 * v + 2];
            }
            else
            {
                __set(P, m, r, 2 * v + 2, V);
                a[v] = a[2 * v + 1] + a[2 * v + 2];
            }
        }

        public:
        int Summ(int L, int R)
        {
            if (R < L)
                return 0;
            return __summ(L, R + 1, l, r, 0);
        }

        void Set(int P, int V)
        {
            __set(P, l, r, 0, V);
        }

        Summ_Segment_Tree(int _n)
        {
            a.resize(4 * _n);
            l = 0, r = _n;
        }
    };

    long long inq(long long x, long long q, long long MOD)
    {
        if (q == 0)
            return 1;
        long long l = inq(x, q / 2, MOD);
        if (q % 2)
            return l * l % MOD * x % MOD;
        return l * l % MOD;
    }
};


using namespace MySpace;

#define F(i, n) for (int (i) = 0; (i) != (n); (i)++)
#define fi first
#define se second
#define re return
#define all(x) (x).begin(), (x).end()

#define int long long

const ll MOD = 1e9 + 7;
const ll K = 320;
ll n, q;
ll cntC[100001];

struct Edge{
    int a, b;
    int c, d;
};
vector<Edge> s;
vector<int> graph[100001];

int go(int v, int id)
{
    return s[id].a + s[id].b - v;
}
int get(int id)
{
    return s[id].d;
}

vector<int> euler;
int F[100001];
int L[100001];
int vis[100001];
int H[200001];
int h[200001];
pii sparce[20][200001];
int in[200001];
int out[200001];
int Timer = 1;
int dist[200001];

void dfs(int v, int dist_param)
{
    dist[v] = dist_param;
    in[v] = Timer++;
    vis[v] = 1;
    F[v] = euler.size();
    L[v] = euler.size();
    euler.push_back(v);
    for (int i = 0; i < graph[v].size(); i++)
    {
        int u = go(v, graph[v][i]);
        if (vis[u] == 0)
        {
            h[u] = h[v] + 1;
            dfs(u, dist_param + get(graph[v][i]));
            L[v] = euler.size();
            euler.push_back(v);
        }
    }
    out[v] = Timer++;
}

int pred(int p, int s)
{
    return (in[p] <= in[s] && out[s] <= out[p]);
}

int run(int ID, int V)
{
    int l = s[ID].a;
    int r = s[ID].b;
    if (pred(l, V) && pred(r, V))
        return 1;
    return 0;
}

pii MinG(int l, int r)
{
    int len = r - l + 1;
    int hh = H[len];
    return min(sparce[hh][l], sparce[hh][r - (1 << hh) + 1]);
}

int LCA(int v, int u)
{
    re MinG(min(F[v], F[u]), max(L[v], L[u])).second;
}

int x[100001];
int y[100001];
int lca[100001];
int u[100001];
int v[100001];
int ans[100001];

vector<int> edges_of_color[100001];
vector<int> query_of_color[100001];

void solve_small(int c)
{
    for (int i = 0; i < query_of_color[c].size(); i++)
    {
        int Y = y[query_of_color[c][i]];
        int U = u[query_of_color[c][i]];
        int V = v[query_of_color[c][i]];
        int Lca = lca[query_of_color[c][i]];
        int Now_ans = dist[U] + dist[V] - 2 * dist[Lca];
        for (int j = 0; j < edges_of_color[c].size(); j++)
        {
            int ID = edges_of_color[c][j];
            if (run(ID, U) && !run(ID, Lca))
            {
                Now_ans -= s[ID].d;
                Now_ans += Y;
            }
            if (run(ID, V) && !run(ID, Lca))
            {
                Now_ans -= s[ID].d;
                Now_ans += Y;
            }
        }
        ans[query_of_color[c][i]] = Now_ans;
    }
}

int count[100001];
int summ[100001];
int viss[100001];

void _dfs(int v, int c, int p1, int p2)
{
    count[v] = p1;
    summ[v] = p2;
    viss[v] = 1;
    for (int i = 0; i < graph[v].size(); i++)
    {
        int u = go(v, graph[v][i]);
        if (viss[u] == 0)
        {
            int color = s[graph[v][i]].c;
            if (color == c)
            {
                p1++;
                p2 += get(graph[v][i]);
            }
            _dfs(u, c, p1, p2);
            if (color == c)
            {
                p1--;
                p2 -= get(graph[v][i]);
            }
        }
    }
}

void solve_big(int c)
{
    for (int i = 1; i <= n; i++)
    {
        count[i] = 0;
        summ[i] = 0;
        viss[i] = 0;
    }
    _dfs(1, c, 0, 0);
    for (int i = 0; i < query_of_color[c].size(); i++)
    {
        int Y = y[query_of_color[c][i]];
        int U = u[query_of_color[c][i]];
        int V = v[query_of_color[c][i]];
        int Lca = lca[query_of_color[c][i]];
        int Now_ans = dist[U] + dist[V] - 2 * dist[Lca];
        
        //cout << c << " " << U << " " << summ[U] << " " << count[U] << endl;
        //cout << c << " " << V << " " << summ[V] << " " << count[V] << endl;
        //cout << c << " " << Lca << " " << summ[Lca] << " " << count[Lca] << endl;
        Now_ans -= summ[U];
        Now_ans += count[U] * Y;

        Now_ans -= summ[V];
        Now_ans += count[V] * Y;

        Now_ans += summ[Lca];
        Now_ans -= count[Lca] * Y;

        Now_ans += summ[Lca];
        Now_ans -= count[Lca] * Y;

        ans[query_of_color[c][i]] = Now_ans;
    }
}

signed main()
{
    H[1] = 0;
    H[2] = 0;
    H[3] = 1;
    for (int i = 4; i <= 200000; i++)
    {
        H[i] = H[i - 1];
        if (((i - 1) & (i - 2)) == 0)
            H[i]++;
    }
    ios_base::sync_with_stdio();
    cin.tie(0);
    cout.tie(0);
    cin >> n >> q;
    for (int i = 0; i < n - 1; i++)
    {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        cntC[c]++;
        graph[a].push_back(i);
        graph[b].push_back(i);
        s.push_back({a, b, c, d});
        edges_of_color[c].push_back(i);
    }
    dfs(1, 0);
    for (int i = 0; i < euler.size(); i++)
    {
        sparce[0][i] = {h[euler[i]], euler[i]};
    }

    for (int j = 1; j < 20; j++)
    {
        for (int i = 0; i + (1 << j) - 1 < euler.size(); i++)
        {
            sparce[j][i] = MinG(i, i + (1 << j) - 1);
        }
    }

    for (int i = 0; i < q; i++)
    {
        cin >> x[i] >> y[i] >> u[i] >> v[i];
        lca[i] = LCA(u[i], v[i]);
        query_of_color[x[i]].push_back(i);
    }

    for (int i = 1; i <= n - 1; i++)
    {
        if (cntC[i] >= K)
        {
            solve_big(i);
        }
        else
        {
            solve_small(i);
        }
    }

    for (int i = 0; i < q; i++)
    {
        cout << ans[i] << "\n";
    }
}


Measured memory_bytes: 73580