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<cstdio>
#include<algorithm>
using namespace std;
int n,T,num,tot;
int rdt[200300],rd[200300],rdc[200300],rdl[200300],wz[200300],ans[200300];
int dad[200300],hvdad[200300],hvson[200300],dep[200300],sz[200300],dadlen[200300];
int trtoli[200300],litotr[200300];
int a[400300],sum[400300],L[400300],R[400300];

struct SS
{
  int ans,sum;
};

struct S
{
  int l,c,x,y,n;
}A[200050],Q[200050];


void cnct(int x,int y,int c,int l)
{
  rdt[++num]=wz[x],rd[num]=y,rdc[num]=c,rdl[num]=l,wz[x]=num;
  rdt[++num]=wz[y],rd[num]=x,rdc[num]=c,rdl[num]=l,wz[y]=num;
}

void dfs(int x,int from,int l,int d)
{
  int t=wz[x],m=0;
  dad[x]=from,sz[x]=1,dadlen[x]=l,dep[x]=d;
  while(t)
    {
      if(rd[t]!=from)
        {
		  dfs(rd[t],x,rdl[t],d+1);
		  if(sz[rd[t]]>m) m=sz[rd[t]],hvson[x]=rd[t];
		  sz[x]++;
		}
	  t=rdt[t];
	}
}

void dfs2(int x,int hd)
{
  int t=wz[x];
  trtoli[x]=++num,hvdad[x]=hd;
  litotr[num]=x;
  if(hvson[x]) dfs2(hvson[x],hd);
  while(t)
    {
      if(rd[t]!=dad[x] && rd[t]!=hvson[x])
        {
		  dfs2(rd[t],rd[t]);
		}
	  t=rdt[t];
	}
}

void Mk(int x,int l,int r)
{
  L[x]=l,R[x]=r;
  if(l!=r)
    {
	  Mk(x*2,l,(l+r)/2);
	  Mk(x*2+1,(l+r)/2+1,r);
	  a[x]=a[x*2]+a[x*2+1];
	}
  else
    {
	  a[x]=dadlen[litotr[l]];
	}
}

bool cmp(S t1,S t2)
{
  return t1.c<t2.c;
}

void updt(int x,int tar,int num,int ty)
{
  if(L[x]==R[x])
    {
	  a[x]=num,sum[x]=ty; 
	}
  else
    {
	  if(tar<L[x*2+1]) updt(x*2,tar,num,ty);
	  else updt(x*2+1,tar,num,ty);
	  a[x]=a[x*2]+a[x*2+1];
	  sum[x]=sum[x*2]+sum[x*2+1];
	}
}

void chg(int x,int y)
{
  int tar,tarnum=y;
  if(dad[A[x].x]==A[x].y) tar=trtoli[A[x].x];
  else tar=trtoli[A[x].y];
  updt(1,tar,tarnum,1);
}

void rechg(int x)
{
  int tar,tarnum=A[x].l;
  if(dad[A[x].x]==A[x].y) tar=trtoli[A[x].x];
  else tar=trtoli[A[x].y];
  updt(1,tar,tarnum,0);
}


SS getsum(int x,int l,int r)
{
  if(L[x]==l && R[x]==r) 
    {
	  SS P;
	  P.ans=a[x];
	  P.sum=sum[x];
	  return P;
	}
  else
    {
	  if(r<L[x*2+1]) return getsum(x*2,l,r);
	  else if(l>R[x*2]) return getsum(x*2+1,l,r);
	  else 
	    {
		  SS P=getsum(x*2,l,R[x*2]),PP=getsum(x*2+1,L[x*2+1],r);
		  P.ans+=PP.ans,P.sum+=PP.sum;
		  return P;
		}
	}
}

int getans(int x,int y,int t1,int t2)
{
  int ans=0,sum=0;
  SS P;
  while(hvdad[x]!=hvdad[y])
    {
	  if(dep[hvdad[x]]<dep[hvdad[y]]) swap(x,y);
	  P=getsum(1,trtoli[hvdad[x]],trtoli[x]);
	  ans+=P.ans,sum+=P.sum;
	  x=dad[hvdad[x]];
	}
  if(x!=y)
  {
  if(dep[x]<dep[y]) swap(x,y);
    P=getsum(1,trtoli[y]+1,trtoli[x]);
	  ans+=P.ans,sum+=P.sum;
  }
  return ans+sum*(Q[t2].l-Q[t1].l);
} 

int main()
{
  int i,j,k,i2,j2;
  scanf("%d%d",&n,&T);
  for(i=1;i<n;i++)
    {
     scanf("%d%d%d%d",&A[i].x,&A[i].y,&A[i].c,&A[i].l);
     cnct(A[i].x,A[i].y,A[i].c,A[i].l),A[i].n=i;
	}
  for(i=1;i<=T;i++) scanf("%d%d%d%d",&Q[i].c,&Q[i].l,&Q[i].x,&Q[i].y),Q[i].n=i;
  num=0;
  dfs(1,0,0,0);
  dfs2(1,1);
  Mk(1,1,num);
  sort(A+1,A+n,cmp);
  sort(Q+1,Q+1+T,cmp);
  i2=0;
 for(i=1;i<=T;i++)
    {
      int pd=0;
      while(A[++i2].c<Q[i].c && i2<n);
      if(A[i2].c==Q[i].c)
        {
		  for(j2=i2;A[j2].c==Q[i].c;j2++)
		    {
			  chg(j2,Q[i].l);
			}
		  pd=1;
		}
	  else i2--;
	  for(j=i+1;j<=T;j++) if(Q[j].c!=Q[i].c) break;
	  for(k=i;k<j;k++)
	    {
		  ans[Q[k].n]=getans(Q[k].x,Q[k].y,i,k);
		}
	  if(pd)
	    {
		  for(j2=i2;A[j2].c==Q[i].c;j2++)
		    {
			  rechg(j2);
			}
		  i2=j2-1;
		}
	  i=j-1;
	}
  for(i=1;i<=T;i++) printf("%d\n",ans[i]);
}