#[allow(dead_code)]
mod persistent_array {
    use std::cmp::Ordering;
    use std::rc::Rc;
    pub struct Head<T: Clone> {
        root: Link<T>,
    }
    impl<T: Clone> Head<T> {
        pub fn new(n: usize, ini: T) -> Head<T> {
            Head {
                root: Node::build_by(&vec![ini; n])
            }
        }
        pub fn build_by(a: &[T]) -> Head<T> {
            Head {
                root: Node::build_by(a),
            }
        }
        pub fn get_at(&self, k: usize) -> Option<&T> {
            Node::get_at(&self.root, k)
        }
        pub fn set_at(&self, k: usize, val: T) -> Head<T> {
            let r = self.root.clone();
            Head {
                root: Node::set_at(r, k, val),
            }
        }
    }
    type Link<T> = Option<Rc<Node<T>>>;
    struct Node<T: Clone> {
        val: T,
        size: usize,
        left: Link<T>,
        right: Link<T>,
    }
    impl<T: Clone> Node<T> {
        fn get_size(t: &Link<T>) -> usize {
            match t.as_ref() {
                None => 0,
                Some(t) => t.size,
            }
        }
        fn new_node(l: Link<T>, r: Link<T>, val: T) -> Link<T> {
            Some(Rc::new(Node {
                val: val,
                size: Node::get_size(&l) + Node::get_size(&r) + 1,
                left: l,
                right: r,
            }))
        }
        fn build_by(a: &[T]) -> Link<T> {
            if a.len() == 0 {
                None
            } else if a.len() == 1 {
                Node::new_node(None, None, a[0].clone())
            } else {
                let n = a.len();
                let m = n / 2;
                Node::new_node(Node::build_by(&a[..m]), Node::build_by(&a[(m + 1)..]), a[m].clone())
            }
        }
        fn get_at(t: &Link<T>, k: usize) -> Option<&T> {
            assert!(k < Node::get_size(t));
            let t = t.as_ref().unwrap();
            let l_size = Node::get_size(&t.left);
            match l_size.cmp(&k) {
                Ordering::Equal => {
                    Some(&t.val)
                },
                Ordering::Greater => {
                    Node::get_at(&t.left, k)
                },
                Ordering::Less => {
                    Node::get_at(&t.right, k - l_size - 1)
                },
            }
        }
        fn set_at(t: Link<T>, k: usize, val: T) -> Link<T> {
            assert!(k < Node::get_size(&t));
            let t = t.unwrap();
            let l_size = Node::get_size(&t.left);
            match l_size.cmp(&k) {
                Ordering::Equal => {
                    Node::new_node(t.left.clone(), t.right.clone(), val)
                },
                Ordering::Greater => {
                    let l = Node::set_at(t.left.clone(), k, val);
                    Node::new_node(l, t.right.clone(), t.val.clone())
                }
                Ordering::Less => {
                    let r = Node::set_at(t.right.clone(), k - l_size - 1, val);
                    Node::new_node(t.left.clone(), r, t.val.clone())
                },
            }
        }
    }
}
use std::io::{Read, Write};

fn calc_lca(mut a: usize, mut b: usize, db: &Vec<Vec<usize>>, depth: &[usize]) -> usize {
    if depth[a] > depth[b] {
        std::mem::swap(&mut a, &mut b);
    }
    for i in (0..db.len()).rev() {
        if ((depth[b] - depth[a]) >> i) & 1 == 1 {
            b = db[i][b];
        }
    }
    if a == b {
        return a;
    }
    for i in (0..db.len()).rev() {
        if db[i][a] != db[i][b] {
            a = db[i][a];
            b = db[i][b];
        }
    }
    db[0][a]
}

fn run() {
    let mut s = String::new();
    std::io::stdin().read_to_string(&mut s).unwrap();
    let mut it = s.trim().split_whitespace();
    let n: usize = it.next().unwrap().parse().unwrap();
    let q: usize = it.next().unwrap().parse().unwrap();
    let mut g = vec![vec![]; n];
    for _ in 1..n {
        let a = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let b = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let c = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let d = it.next().unwrap().parse::<usize>().unwrap();
        g[a].push((b, c, d));
        g[b].push((a, c, d));
    }
    let mut parent = vec![0; n];
    let mut depth = vec![0; n];
    let mut dp = vec![0; n];
    let mut h: Vec<Option<persistent_array::Head<(usize, usize)>>> = (0..n).map(|_| None).collect();
    h[0] = Some(persistent_array::Head::new(n - 1, (0, 0)));
    let mut stack = vec![0];
    while let Some(v) = stack.pop() {
        for &(u, c, d) in &g[v] {
            if u == parent[v] {
                continue;
            }
            parent[u] = v;
            depth[u] = depth[v] + 1;
            dp[u] = dp[v] + d;
            let t = h[v].take().unwrap();
            let &(cnt, sum) = t.get_at(c).unwrap();
            let s = t.set_at(c, (cnt + 1, sum + d));
            h[u] = Some(s);
            h[v] = Some(t);
            stack.push(u);
        }
    }
    let mut doubling = vec![parent];
    for i in 1..17 {
        doubling.push(vec![0; n]);
        for j in 0..n {
            doubling[i][j] = doubling[i - 1][doubling[i - 1][j]];
        }
    }
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());
    for _ in 0..q {
        let x = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let y = it.next().unwrap().parse::<usize>().unwrap();
        let u = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let v = it.next().unwrap().parse::<usize>().unwrap() - 1;
        let mut ans = 0;
        for &v in [u, v].iter() {
            let &(cnt, sum) = (&h[v]).as_ref().unwrap().get_at(x).unwrap();
            ans += dp[v] - sum + cnt * y;
        }
        let p = calc_lca(u, v, &doubling, &depth);
        let &(cnt, sum) = (&h[p]).as_ref().unwrap().get_at(x).unwrap();
        ans -= 2 * (dp[p] - sum + cnt * y);
        writeln!(out, "{}", ans).unwrap();
    }
}

fn main() {
    run();
}


Measured memory_bytes: 158456