Problem:
Score : 600 points

Problem Statement

There is a tree with N vertices numbered 1 to N.
The i-th edge in this tree connects Vertex a_i and Vertex b_i, and the color and length of that edge are c_i and d_i, respectively.
Here the color of each edge is represented by an integer between 1 and N-1 (inclusive). The same integer corresponds to the same color, and different integers correspond to different colors.

Answer the following Q queries:

Query j (1 \leq j \leq Q): assuming that the length of every edge whose color is x_j is changed to y_j, find the distance between Vertex u_j and Vertex v_j. (The changes of the lengths of edges do not affect the subsequent queries.)

Constraints

2 \leq N \leq 10^5

1 \leq Q \leq 10^5

1 \leq a_i, b_i \leq N

1 \leq c_i \leq N-1

1 \leq d_i \leq 10^4

1 \leq x_j \leq N-1

1 \leq y_j \leq 10^4

1 \leq u_j < v_j \leq N

The given graph is a tree.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N Q
a_1 b_1 c_1 d_1
:
a_{N-1} b_{N-1} c_{N-1} d_{N-1}
x_1 y_1 u_1 v_1
:
x_Q y_Q u_Q v_Q

Output

Print Q lines. The j-th line (1 \leq j \leq Q) should contain the answer to Query j.

Sample Input 1

5 3
1 2 1 10
1 3 2 20
2 4 4 30
5 2 1 40
1 100 1 4
1 100 1 5
3 1000 3 4

Sample Output 1

130
200
60

The graph in this input is as follows:

Here the edges of Color 1 are shown as solid red lines, the edge of Color 2 is shown as a bold green line, and the edge of Color 4 is shown as a blue dashed line.

Query 1: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 4 is 100 + 30 = 130.

Query 2: Assuming that the length of every edge whose color is 1 is changed to 100, the distance between Vertex 1 and Vertex 5 is 100 + 100 = 200.

Query 3: Assuming that the length of every edge whose color is 3 is changed to 1000 (there is no such edge), the distance between Vertex 3 and Vertex 4 is 20 + 10 + 30 = 60. Note that the edges of Color 1 now have their original lengths.

Solution in Rust (1.15.1) (judge verdict: Accepted)

#[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();
}