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)

use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

type Weight = (i64, i64);
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

#[allow(dead_code)]
struct LCA {
    log_size: usize,
    parent: Vec<Vec<usize>>,
    depth: Vec<usize>,
}
#[allow(dead_code)]
impl LCA {
    fn new(g: &Graph, root: usize) -> LCA {
        let n = g.len();
        let mut log_size = 0;
        while (1 << log_size) <= n {
            log_size += 1;
        }
        let mut parent = vec![vec![root; log_size]; n];
        let mut depth = vec![0; n];

        let mut que = vec![];
        que.push(root);
        while let Some(node) = que.pop() {
            for edge in g[node].iter() {
                if edge.dest == parent[node][0] {
                    continue;
                }
                parent[edge.dest][0] = node;
                depth[edge.dest] = depth[node] + 1;
                que.push(edge.dest);
            }
        }

        for iter in 0..log_size - 1 {
            for i in 0..n {
                parent[i][iter + 1] = parent[parent[i][iter]][iter];
            }
        }
        LCA {
            log_size: log_size,
            parent: parent,
            depth: depth,
        }
    }

    fn lca(&self, mut u: usize, mut v: usize) -> usize {
        if self.depth[u] > self.depth[v] {
            std::mem::swap(&mut u, &mut v);
        }
        for i in 0..self.log_size {
            if (((self.depth[u] ^ self.depth[v]) >> i) & 1) == 1 {
                v = self.parent[v][i];
            }
        }
        if u == v {
            return u;
        }
        for i in (0..self.log_size).rev() {
            if self.parent[u][i] != self.parent[v][i] {
                u = self.parent[u][i];
                v = self.parent[v][i];
            }
        }
        return self.parent[u][0];
    }
}

#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
struct Query {
    color: i64,
    d: i64,
    f: usize,
    t: usize,
    index: usize,
}

impl Query {
    fn new(color: i64, d: i64, f: usize, t: usize, index: usize) -> Query {
        Query {
            color: color,
            d: d,
            f: f,
            t: t,
            index: index,
        }
    }
}

fn calc_dist(
    g: &Graph,
    from: usize,
    parent: usize,
    color: i64,
    cnt: usize,
    d: i64,
    results: &mut Vec<(usize, i64)>,
) {
    results[from] = (cnt, d);
    for e in g[from].iter() {
        if e.dest == parent {
            continue;
        }
        let mut ncnt = cnt;
        let mut nd = d;
        if color == -1 || e.weight.1 == color {
            ncnt += 1;
            nd += e.weight.0;
        }
        calc_dist(g, e.dest, from, color, ncnt, nd, results);
    }
}

fn main() {
    let n = read::<usize>();
    let q = read::<usize>();
    let mut g = graph_new(n);
    let mut index = 0;
    let mut color_edges = vec![vec![]; n];
    for _i in 0..n - 1 {
        let a = read::<usize>() - 1;
        let b = read::<usize>() - 1;
        let c = read::<i64>() - 1;
        let d = read::<i64>();
        color_edges[c as usize].push(Edge::new(index, a, b, (d, c)));
        add_bi_edge(&mut g, &mut index, a, b, (d, c));
    }
    let mut query_color_cnts = vec![0; n];
    let mut queries = vec![Query::new(0, 0, 0, 0, 0); q];
    for i in 0..q {
        queries[i].color = read::<i64>() - 1;
        queries[i].d = read::<i64>();
        queries[i].f = read::<usize>() - 1;
        queries[i].t = read::<usize>() - 1;
        queries[i].index = i;
        query_color_cnts[queries[i].color as usize] += 1;
    }
    queries.sort_by_key(|query| query.color);
    let mut anss = vec![0; q];
    let lca = LCA::new(&g, 0);
    let mut base_dists = vec![(0, 0); n];
    calc_dist(&g, 0, 0, -1, 0, 0, &mut base_dists);
    let mut color_dists = vec![(0, 0); n];
    let mut has_color_dists = false;
    let mut prev_color = -1;
    for i in 0..q {
        let color = queries[i].color;
        let d = queries[i].d;
        let f = queries[i].f;
        let t = queries[i].t;
        if prev_color != color {
            prev_color = color;
            if (color_edges[color as usize].len() * query_color_cnts[color as usize]) as f64 > n as f64 / (n as f64).log2() {
                calc_dist(&g, 0, 0, color, 0, 0, &mut color_dists);
                has_color_dists = true;
            } else {
                has_color_dists = false;
            }
        }
        let l = lca.lca(f, t);
        let mut ans = base_dists[f].1 + base_dists[t].1 - base_dists[l].1 * 2;
        if has_color_dists {
            let cnt = color_dists[f].0 + color_dists[t].0 - color_dists[l].0 * 2;
            let total_weight = color_dists[f].1 + color_dists[t].1 - color_dists[l].1 * 2;
            ans += cnt as i64 * d - total_weight;
        } else {
            for e in color_edges[color as usize].iter() {
                let mut from = e.src;
                let mut to = e.dest;
                if lca.depth[from] > lca.depth[to] {
                    std::mem::swap(&mut from, &mut to);
                };
                if lca.depth[to] <= lca.depth[l] {
                    continue;
                }
                if lca.lca(to, f) == to || lca.lca(to, t) == to {
                    // hit
                    ans += d - e.weight.0;
                }
            }
        }
        anss[queries[i].index] = ans;
    }
    for i in 0..q {
        println!("{}", anss[i]);
    }
}