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: Time Limit Exceeded)

#[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);
    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, &adj, &parents, &dists);
        let dist_u = dists[u][n - 1].1 - dists[u][x].1 + dists[u][x].0 * y;
        let dist_v = dists[v][n - 1].1 - dists[v][x].1 + dists[v][x].0 * y;
        let dist_lca = dists[lca][n - 1].1 - dists[lca][x].1 + dists[lca][x].0 * y;
        let dist = dist_u + dist_v - dist_lca;
        println!("{}", dist);
    }
}

fn preprocess(adj: &Vec<Vec<(usize, usize, usize)>>) -> (Vec<Vec<usize>>, Vec<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![vec![(0, 0); n]; 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, col, length) in adj[crt].iter() {
            if used[nxt] {
                continue;
            }
            parents[nxt][0] = crt;
            dists[nxt] = dists[crt].clone();
            dists[nxt][col] = (dists[crt][col].0 + 1, dists[crt][col].1 + length);
            dists[nxt][n - 1] = (dists[crt][n - 1].0 + 1, dists[crt][n - 1].1 + length);
            stack.push(nxt);
        }
    }
    for i in 1..((n as f64).log2() as usize) {
        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, adj: &[Vec<(usize, usize, usize)>], parents: &[Vec<usize>], dists: &[Vec<(usize, usize)>]) -> usize {
    let n = adj.len();
    let (mut u, mut v) = (u, v);
    if dists[u][n - 1].0 < dists[v][n - 1].0 {
        swap(&mut u, &mut v);
    }
    while dists[u][n - 1].0 > dists[v][n - 1].0 {
        let diff = ((dists[u][n - 1].0 - dists[v][n - 1].0) as f64).log2() as usize;
        u = parents[u][diff];
    }
    if u == v {
        return u;
    }
    while u != v {
        let mut depth = (dists[u][n - 1].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
}

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