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 C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const ull mod = 1e9 + 7;
#define REP(i,n) for(int i=0;i<(int)n;++i)

//debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;

template<class S, class T> ostream& operator << (ostream& os, const pair<S, T> v){
  os << "(" << v.first << ", " << v.second << ")"; return os;
}
template<class T> ostream& operator << (ostream& os, const vector<T> v){
  for(int i = 0; i < v.size(); i++){if(i > 0){os << " ";} os << v[i];} return os;
}
template<class T> ostream& operator << (ostream& os, const vector<vector<T>> v){
  for(int i = 0; i < v.size(); i++){if(i > 0){os << endl;} os << v[i];} return os;
}

// RMQ

typedef ll Val;
typedef pair<Val, Val> pVV;
const Val INF_Val = LLONG_MAX;
const int ME = 18;
const int MN = 1<<ME;
class RMQ_segtree{
public:
    pVV dat[2*MN-1];
    RMQ_segtree(){
        REP(i, 2*MN-1) dat[i] = make_pair(INF_Val, -1);
    }

    void update(int k, Val a){
        //k番目の要素をaに変更
        k += MN-1;
        dat[k] = make_pair(a, k-(MN-1));
        while(k>0){
            k = (k-1)/2;
            dat[k] = min(dat[2*k+1], dat[2*k+2]);
        }
    }

   pVV recursion(int a, int b, int k, int l, int r){
        //最小値計算用の再帰関数
        if(r<=a || b<=l) return make_pair(INF_Val, -1);
        if(a<=l && r<=b) return dat[k];
        else{
            pVV vl = recursion(a, b, 2*k+1, l, (l+r)/2);
            pVV vr = recursion(a, b, 2*k+2, (l+r)/2, r);
            return min(vl, vr);
        }
    }

    pVV minimum(int a, int b){
        //区間[a, b)の最小値
        return recursion(a, b, 0, 0, MN);
    }

    void print_val(int a, int b){
        //区間[a, b)の値を出力
        for(int i=a;i<b;i++) cout << dat[i+MN-1].first << endl;
        cout << endl;
    }
};

// LCA

const ll MAX_N = 101010;

vector<ll> G[MAX_N];
ll vs[2*MAX_N-1];
ll depth[2*MAX_N-1];
ll id[MAX_N];
RMQ_segtree rmq;

void dfs(ll now, ll par, ll d, ll &k){
    id[now] = k;
    vs[k] = now;
    depth[k] = d;
    k++;
    REP(i, G[now].size()){
        ll next = G[now][i];
        if(next == par) continue;
        dfs(next, now, d+1, k);
        vs[k] = now;
        depth[k] = d;
        k++;
    }
}

void init(ll N){
    ll k = 0;
    dfs(0, -1, 0, k);
    REP(i, 2*N-1) rmq.update(i, depth[i]); 
}

ll lca(ll u, ll v){
    ll mi = min(id[u], id[v]);
    ll ma = max(id[u], id[v]);
    return vs[rmq.minimum(mi, ma+1).second];
}

struct edge{
    ll to, col, len;
};

ll N, Q;
vector<edge> T[MAX_N];
vector<pll> dist_col[MAX_N];
vector<pll> num_col[MAX_N];
vector<ll> dist_node(MAX_N, 0);
vector<ll> dist_col_tmp(MAX_N, 0);
vector<ll> num_col_tmp(MAX_N, 0);


void colorful_dfs(ll now, ll par, ll dist, ll &k){
    k++;
    ll to_par_col, to_par_len;
    REP(i, T[now].size()){
        edge e = T[now][i];
        if(e.to == par){
            to_par_col = e.col;
            to_par_len = e.len;
            continue;
        }
        num_col_tmp[e.col]++;
        dist_col_tmp[e.col] += e.len;
        dist_node[e.to] = dist+e.len;
        num_col[e.col].push_back({k,  num_col_tmp[e.col]});
        dist_col[e.col].push_back({k, dist_col_tmp[e.col]});

        colorful_dfs(e.to, now, dist+e.len, k);
        k++;
    }
    if(now != 0){
        num_col_tmp[to_par_col]--;
        dist_col_tmp[to_par_col] -= to_par_len;
        num_col[to_par_col].push_back({k,  num_col_tmp[to_par_col]});
        dist_col[to_par_col].push_back({k, dist_col_tmp[to_par_col]});
    }
}

ll colorful_dist(ll node, ll col, ll val){
    ll res = dist_node[node];

    ll seq = id[node];
    pll key = {seq, (1ll<<60)};

    auto itr1 = upper_bound(num_col[col].begin(), num_col[col].end(), key);
    itr1--;
    res += val * itr1->second;
    
    auto itr2 = upper_bound(dist_col[col].begin(), dist_col[col].end(), key);
    itr2--;
    res -= itr2->second;

    return res;
}


int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> N >> Q;

    REP(i, MAX_N){
        num_col[i].push_back({0, 0});
        dist_col[i].push_back({0, 0});
    }

    REP(i, N-1){
        ll a, b, c, d;
        cin >> a >> b >> c >> d;
        a--, b--;
        edge e = {b, c, d};
        edge f = {a, c, d};
        G[a].push_back(b);
        G[b].push_back(a);
        T[a].push_back(e);
        T[b].push_back(f);
    }
    init(N);

    ll k = 0;
    colorful_dfs(0, -1, 0, k);

    /*
    REP(i, 2*N-1){
        cout << vs[i] << " ";
    }
    cout << endl;

    REP(i, N){
        cout << dist_node[i] << " ";
    }
    cout << endl;

    REP(i, N){
        cout << id[i] << " ";
    }
    cout << endl;

    REP(i, N){
        cout << i << ": " << " ";
        REP(j, num_col[i].size()){
            cout << num_col[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
    REP(i, N){
        cout << i << ": " << " ";
        REP(j, dist_col[i].size()){
            cout << dist_col[i][j] << " ";
        }
        cout << endl;
    }
    */
    
    REP(q, Q){
        ll x, y, u, v;
        cin >> x >> y >> u >> v;
        u--, v--;
        ll w = lca(u, v);
        cout << colorful_dist(v, x, y) + colorful_dist(u, x, y) - 2*colorful_dist(w, x, y) << endl;
    }
    

    return 0;
}