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: Wrong Answer)

// #pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")

#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>

using namespace std ;
using namespace __gnu_pbds;

#define reMin(a, b) a = min(a, b)
#define reMax(a, b) a = max(a, b)

#define lint long long
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define SET(x, val) memset(x, val, sizeof(x))
#define fastio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)

typedef vector < int > vi ;
typedef pair < int, int > pii ;

const int N = 1e6 + 2 ;
const int MOD = 1e9 + 7 ;
const lint INF = 1e18 ;

vector<int> a[N];
int sz[N];
int level[N];
int par[N]; int atTime[N] ;
pii thisTime[N] ;
int tin[N], tout[N];
int w[N];
int n, q ;
int X, Y ;
int timer = 0;

/*
struct HASH{
  size_t operator()(const pair<int,int>&x)const{
    return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
  }
};
*/
// unordered_map< pair <int,int>,int,HASH> wt, length ;
// unordered_map < pair < int, int > , int > wt, length ;
map < pair < int, int > , int > wt, length ;

bool cmp(int x, int y)
{
    return sz[x] > sz[y] ;
}

void dfs(int v, int p = -1) {
	par[v] = p;
	auto it = find(all(a[v]), p);
	if (it != a[v].end()) {
		a[v].erase(it);
	}
	for (int x : a[v]) {
		level[x] = level[v] + 1;
		dfs(x, v);
		sz[v] += sz[x];
	}
	++sz[v];
	sort(all(a[v]), cmp);
}

inline int get(int t1, int t2)
{
    int ans = 0 ;
    for(int i = t1; i < t2; i++)
    {
        if(thisTime[i].first == X) ans += Y ;
        else ans += thisTime[i].second ;
        // cout << atTime[i] << endl ;
    }
    return ans ;
}

void dfsOrder(int v, int p = -1) {
    if(p != -1)
        thisTime[timer] = { wt[{v, p}], length[{v, p}] } ;
    else
        thisTime[timer] = {0, 0} ;

    atTime[timer] = v ;

	tin[v] = timer++;
	if (!a[v].empty()) {
		w[a[v][0]] = w[v];
	}
	for (int x : a[v]) {
		dfsOrder(x, v);
	}
	tout[v] = timer;
}

bool isPar(int u, int v) {
	return tin[u] <= tin[v] && tout[u] >= tout[v];
}

int getAnswer(int u, int v)
{
    int ans = 0 ;
    // cout << "Doing " << u << endl ;
	while (!isPar(w[u], v)) {
        ans += get(tin[w[u]], tin[u] + 1);
		u = par[w[u]];
		// cout << u << endl ;
	}
	// cout << "Doing " << v << endl ;
	while (w[v] != w[u]) {
        ans += get(tin[w[v]], tin[v] + 1);
		v = par[w[v]];
		/// cout << v << endl ;
	}
	// cout << "Merging " << ans << endl ;
	ans += get(min(tin[u], tin[v]), max(tin[u], tin[v]) + 1 );
	// cout << endl ;
	return ans ;
}

int main()
{
    fastio; cin >> n >> q ; int u, v, c, d ;
    for(int i = 1; i < n; i++)
    {
        cin >> u >> v >> c >> d ; u-- ; v-- ;
        wt[{u, v}] = wt[{v, u}] = c ;
        length[{u, v}] = length[{v, u}] = d ;
        a[u].push_back(v); a[v].push_back(u);
    }
    dfs(0);
    iota(w, w+n, 0);
    dfsOrder(0);
    while(q--)
    {
        cin >> X >> Y >> u >> v ; u-- ; v-- ;
        cout << getAnswer(u, v) << "\n" ;
    }
}