//Author: 23forever
#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
#define mp make_pair
#define fi first
#define se second
typedef long long LL;
const int MAXN = 100000;
const int MAXM = 200000;
using namespace std;

inline int read() {
  int x = 0, w = 1;
  char c = ' ';

  while (c < '0' || c > '9') {
    c = getchar();
    if (c == '-') w = -1;
  }
  while (c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (c ^ 48);
    c = getchar();
  }

  return x * w;
}

int rt[MAXN + 5];

struct SegmentTree {
  int tot;
  struct Node {
    int ls, rs, sz, sum;
  } s[MAXN * 60 + 5];
     
#define lson s[p].ls
#define rson s[p].rs
   
  SegmentTree() : tot(0) {
    memset(s, 0, sizeof(s));
  }

  void upd(int p) {
    s[p].sz = s[lson].sz + s[rson].sz;
    s[p].sum = s[lson].sum + s[rson].sum;
  }
 
  void modify(int &p, int l, int r, int x, int val) {
    if (!p) p = ++tot;
    if (l == r) {
      s[p].sz = 1, s[p].sum = val;
      return;
    }
 
    int mid = l + r >> 1;
 
    if (x <= mid) {
      modify(lson, l, mid, x, val);
    } else {
      modify(rson, mid + 1, r, x, val);
    }
    upd(p);
  } 
 
  int querySum(int p, int l, int r, int x, int y) {
    if (!p) return 0;
    if (x <= l && y >= r) return s[p].sum;
 
    int mid = (l + r) >> 1, ret = 0;
    if (x <= mid) ret = querySum(lson, l, mid, x, y);
    if (y > mid) ret += querySum(rson, mid + 1, r, x, y);
    return ret;
  }
 
  int querySize(int p, int l, int r, int x, int y) {
    if (!p) return 0;
    if (x <= l && y >= r) return s[p].sz;
 
    int mid = (l + r) >> 1, ret = 0;
    if (x <= mid) ret = querySize(lson, l, mid, x, y);
    if (y > mid) ret += querySize(rson, mid + 1, r, x, y);
    return ret;
  }
} Sgt;

int n, m, q;

namespace tree {
  int tot, head[MAXN + 5], idx, id[MAXN + 5], son[MAXN + 5], top[MAXN + 5], sz[MAXN + 5];
  int depth[MAXN + 5], fa[MAXN + 5], val[MAXN + 5];
  
  struct Edge {
    int to, w, c, nxt;
    Edge() {}
    Edge(int _to, int _w, int _c, int _nxt) : to(_to), w(_w), c(_c), nxt(_nxt) {}
  } edge[MAXM + 5];
  
  void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
  }
  
  void addEdge(int u, int v, int c, int w) {
    edge[tot] = Edge(v, w, c, head[u]);
    head[u] = tot++;
    edge[tot] = Edge(u, w, c, head[v]);
    head[v] = tot++;
  }
  
  void dfs(int u) { 
    depth[u] = depth[fa[u]] + 1;
    sz[u] = 1;

    for (int i = head[u]; ~i; i = edge[i].nxt) {
      int v = edge[i].to, c = edge[i].c, w = edge[i].w;
      if (v != fa[u]) {    
        val[v] = val[u] + w, fa[v] = u;
        dfs(v);
        
        sz[u] += sz[v];
        if (sz[son[u]] < sz[v]) son[u] = v;
      }
    }
  }
  
  void buildChain(int u, int topf) {
    id[u] = ++idx;
    top[u] = topf;
    if (!son[u]) return;
   
    buildChain(son[u], topf);
   
    for (int i = head[u]; ~i; i = edge[i].nxt) {
      int v = edge[i].to;
      if (v != fa[u] && v != son[u]) buildChain(v, v);
    }
  }
 
  int queryPathSum(int u, int v, int col) {
    int ret = 0;
   
    while (top[u] != top[v]) {
      if (depth[top[u]] > depth[top[v]]) {
        ret += Sgt.querySum(rt[col], 1, n, id[top[u]], id[u]);
        u = fa[top[u]];
      } else {
        ret += Sgt.querySum(rt[col], 1, n, id[top[v]], id[v]);
        v = fa[top[v]];
      }
    }

    if (u == v) return ret;
     
    if (id[u] < id[v]) {
      ret += Sgt.querySum(rt[col], 1, n, id[son[u]], id[v]);
    } else {
      ret += Sgt.querySum(rt[col], 1, n, id[son[v]], id[u]);
    }
   
    return ret;
  }

  int queryPathNum(int u, int v, int col) {
    //cout << Sgt.querySize(rt[col], 1, n, id[2], id[2]) << endl;

    int ret = 0;
   
    while (top[u] != top[v]) {
      if (depth[top[u]] > depth[top[v]]) {
        ret += Sgt.querySize(rt[col], 1, n, id[top[u]], id[u]);
        u = fa[top[u]];
      } else {
        ret += Sgt.querySize(rt[col], 1, n, id[top[v]], id[v]);
        v = fa[top[v]];
      }
    }

    if (u == v) return ret;
     
    if (id[u] < id[v]) {
      ret += Sgt.querySize(rt[col], 1, n, id[son[u]], id[v]);
    } else {
      ret += Sgt.querySize(rt[col], 1, n, id[son[v]], id[u]);
    }
   
    return ret;
  }

  int lca(int u, int v){
    while (top[u] != top[v]) {
		  if (depth[top[u]] > depth[top[v]]) {
			  u = fa[top[u]];
		  } else {
			  v = fa[top[v]];
			}	
	  }
	  
	  return depth[u] < depth[v] ? u : v;  
  }

  void dfs2(int u) {
    for (int i = head[u]; ~i; i = edge[i].nxt) {
      int v = edge[i].to, c = edge[i].c, w = edge[i].w;
      
      if (v == fa[u]) continue;
      Sgt.modify(rt[c], 1, n, id[v], w);

      dfs2(v);
    }
  }

  void buildTree() {
    dfs(1);
    buildChain(1, 1);
    dfs2(1);

    /*
    for (int i = 1; i <= n; ++i) {
      if (!fa[i]) continue;

    }
   */
    /*
    for (int i = 0; i < tot; i += 2) {
      int v = edge[i].to, u = edge[i ^ 1].to, w = edge[i].w, c = edge[i].c;
      Sgt.modify(rt[c], 1, n, id[v], w);
    }*/
  }

  int getDis(int u, int v) {
    return val[u] + val[v] - 2 * val[lca(u, v)];
  }
}

void init() {
  n = read();
  q = read();
  tree::init();

  for (int i = 1; i < n; ++i) {
    int u = read(), v = read(), c = read(), d = read();
    tree::addEdge(u, v, c, d);
  }
}

int main() {
#ifdef forever23
  freopen("test.in", "r", stdin);
  //freopen("test.out", "w", stdout);
#endif
  init();
  
  tree::buildTree();

  //cout << tree::queryPathSum(4, 5, 1) << endl;

  while (q--) {
    int x = read(), y = read(), u = read(), v = read();
    int res = tree::queryPathNum(u, v, x) * y - tree::queryPathSum(u, v, x);
    printf("%d\n", res + tree::getDis(u, v));
  }

  return 0;
}

Measured memory_bytes: 108032