#[allow(unused_imports)]
use std::cmp::{max, min};
#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::io::prelude::BufRead;
#[allow(unused_imports)]
use std::io::{stdin, stdout, BufReader, BufWriter, Write};
#[allow(unused_imports)]
use std::mem::swap;
#[allow(unused_imports)]
use std::str::FromStr;


fn main() {
	let param = read_vector::<usize>();
    let (n, q) = (param[0], param[1]);
    let mut adj = vec![vec![]; n];
    for _ in 0..(n - 1) {
        let line = read_vector::<usize>();
        let (a, b, c, d) = (line[0] - 1, line[1] - 1, line[2] - 1, line[3]);
        adj[a].push((b, c, d));
        adj[b].push((a, c, d));
    }
    let (parents, dists) = preprocess(&adj);
    let mut queries = vec![];
    let mut qset: HashMap<usize, Vec<usize>> = HashMap::new();
    for _ in 0..q {
        let line = read_vector::<usize>();
        let (x, y, u, v) = (line[0] - 1, line[1], line[2] - 1, line[3] - 1);
        let lca = find_lca(u, v, &parents, &dists);
        queries.push((x, y, u, v, lca));
        for &p in [u, v, lca].into_iter() {
            if qset.contains_key(&p) {
                qset.get_mut(&p).unwrap().push(x);
            } else {
                qset.insert(p, vec![x]);
            }
        }
    }
    let qmap = dfs(&qset, &adj);
    for (x, y, u, v, lca) in queries.into_iter() {
        let col_u = qmap.get(&(u, x)).unwrap();
        let dist_u = dists[u].1 - col_u.1 + col_u.0 * y;
        let col_v = qmap.get(&(v, x)).unwrap();
        let dist_v = dists[v].1 - col_v.1 + col_v.0 * y;
        let col_lca = qmap.get(&(lca, x)).unwrap();
        let dist_lca = dists[lca].1 - col_lca.1 + col_lca.0 * y;
        let dist = dist_u + dist_v - 2 * dist_lca;
        println!("{}", dist);
    }
}

fn preprocess(adj: &Vec<Vec<(usize, usize, usize)>>) -> (Vec<Vec<usize>>, Vec<(usize, usize)>) {
    let n = adj.len();
    let mut parents = vec![vec![std::usize::MAX; (n as f64).log2() as usize + 1]; n];
    let mut dists = vec![(0, 0); n];
    let mut stack = vec![0];
    let mut used = vec![false; n];
    while stack.len() > 0 {
        let crt = stack.pop().unwrap();
        if used[crt] {
            continue;
        }
        used[crt] = true;
        for &(nxt, _, length) in adj[crt].iter() {
            if used[nxt] {
                continue;
            }
            parents[nxt][0] = crt;
            dists[nxt] = dists[crt];
            dists[nxt].0 += 1;
            dists[nxt].1 += length;
            stack.push(nxt);
        }
    }
    for i in 1..((n as f64).log2() as usize + 1) {
        for j in 0..n {
            if parents[j][i - 1] != std::usize::MAX {
                parents[j][i] = parents[parents[j][i - 1]][i - 1];
            }
        } 
    }
    (parents, dists)
}

fn find_lca(u: usize, v: usize, parents: &[Vec<usize>], dists: &[(usize, usize)]) -> usize {
    let (mut u, mut v) = (u, v);
    if dists[u].0 < dists[v].0 {
        swap(&mut u, &mut v);
    }
    while dists[u].0 > dists[v].0 {
        let diff = ((dists[u].0 - dists[v].0) as f64).log2() as usize;
        u = parents[u][diff];
    }
    if u == v {
        return u;
    }
    while u != v {
        let mut depth = (dists[u].0 as f64).log2() as usize;
        while parents[u][depth] == parents[v][depth] && depth > 0 {
            depth -= 1;
        }
        u = parents[u][depth];
        v = parents[v][depth];
    }
    u
}

fn dfs(qset: &HashMap<usize, Vec<usize>>, adj: &[Vec<(usize, usize, usize)>]) -> HashMap<(usize, usize), (usize, usize)> {
    let mut qmap = HashMap::new();
    let mut stack = vec![(0, std::usize::MAX, std::usize::MAX)];
    let mut state = vec![(0, 0); adj.len() - 1];
    let mut used = vec![false; adj.len()];
    while stack.len() > 0 {
        let &(crt, prv, index) = stack.last().unwrap();
        if used[crt] {
            if prv < adj.len() {
                state[adj[prv][index].1].0 -= 1;
                state[adj[prv][index].1].1 -= adj[prv][index].2;
            }
            stack.pop().unwrap();
            continue;
        }
        used[crt] = true;
        if prv < adj.len() {
            state[adj[prv][index].1].0 += 1;
            state[adj[prv][index].1].1 += adj[prv][index].2;
        }
        if qset.contains_key(&crt) {
            for &col in qset.get(&crt).unwrap() {
                qmap.insert((crt, col), state[col]);
            }
        }
        for i in 0..adj[crt].len() {
            if adj[crt][i].0 == prv {
                continue;
            }
            stack.push((adj[crt][i].0, crt, i));
        }
    }
    qmap
}

#[allow(dead_code)]
fn read<T>() -> T where T: std::str::FromStr, T::Err: std::fmt::Debug {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    return buf
        .trim()
        .parse()
        .unwrap();
}

#[allow(dead_code)]
fn read_vector<T>() -> Vec<T> where T: std::str::FromStr, T::Err: std::fmt::Debug {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    return buf
        .split_whitespace()
        .map(|s| s.parse().unwrap())
        .collect();
}

#[allow(dead_code)]
fn read_matrix<T>() -> Vec<Vec<T>> where T: std::str::FromStr, T::Err: std::fmt::Debug {
    use std::io::prelude::*;
    let stdin = stdin();
    return stdin
        .lock()
        .lines()
        .map(|line| line
            .unwrap()
            .split_whitespace()
            .map(|s| s.parse().unwrap())
            .collect())
        .collect();
}

Measured memory_bytes: 85000