/*少说话,多做事*/
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h>
//#include<bits/stdc++.h>
typedef long long ll;

using namespace std;

/*
 n (房子的数量)m(询问的数量)
 n-1行 i j k:      表示房子i与j之间的距离是k
 m行(m次询问)i j : 表示i与j之间的距离是多少

 解题关键:
 ans=dis[u]+dis[v]−2∗dis[lca]

 1.    任选一个点为根节点,从根节点开始
 2.    遍历该点u所有子节点v,并标记这些子节点v已被访问过
 3.    若v还有子节点,返回2,否则进行下一步
 4.    合并v到u上
 5.    寻找与当前点u有询问关系的点v
 6.    若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a

 */

double eps=1e-10;
const ll N=1e5+10; //边的数量(双向边,记住结构体要*2)

struct sss
{
    int to,next,w; //分别代表的是终点、next、权值
}edge[N*2];

int ans[250];         //询问次数不多于200
int val[N];           //用于记录点到根节点的距离
int vis[N];           //用于标记 2:这个点已经遍历过并且回溯过了,1:这个点遍历过但是还没有回溯 ,0:表示这个点还没有遍历
int fa[N];

int n,m;
vector<int>q[N],id[N]; //vector ->   q记录相关联的点,id记录询问的序号(因为所有的询问都是一起输入的,所以用id记录询问的序号,便于最后的输出)

int find(int x)
{
    if(fa[x]==x) return x;
    else return fa[x]=find(fa[x]);
}

int cnt=1;
int head[N]; //head数组初始化-1

void add(int u,int v,int w)   //链式向前星
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    edge[cnt].w=w;
    head[u]=cnt++;
}

void dfs(int x) //从根节点(x)出发开始遍历
{
    vis[x]=1;   //标记x已经被遍历过了
    for(int i=head[x]; i>=0 ; i=edge[i].next)   //遍历与x节点连通的点
    {
        int y=edge[i].to; // y是这条边的终点
        if(vis[y]!=0) continue;    //如果y已经被标记过了,那么continue;
        val[y]=val[x]+edge[i].w;   //y到根节点的距离=x到根节点的距离+两者之间边的权值
        dfs(y);                    //继续对y节点进行子节点的遍历
        fa[y]=x;                   //如果遍历多次过后,y节点没有子节点了,那么将y与x节点连接起来(x节点变为y的父亲节点)
    }

    /*
     如果没有找到与x点的子节点,就是上一个for循环直接不进行,那么就找跟x有关联的点,如果跟y有关联的点vis=0,continue,
     vis=1,找到两者的公共祖先是 跟y有关联的点的祖先(切记,一定是更新完fa数组之后才进行关联点的寻找)
     */

    for(int i=0; i<q[x].size(); i++) //找跟x相关联的点(如果没有的话,这一步直接就没有了)
    {
        int idd=id[x][i];
        int z=q[x][i];       //z是与x相关联的点
        if(vis[z]==2)        //如果z被遍历过且回溯过,那么就可以找x和z的公共祖先
        {
            int w=find(z);    //w为两者的公共祖先(并查集)
            ans[idd]=min(ans[idd],val[x]+val[z]-2*val[w]); //两个询问节点到根节点x的距离-2*最近公共祖先w到根节点x的距离
        }
    }
    vis[x]=2; //将x记录为即遍历又回溯过
}

void init()
{
    cnt=1;
    memset(head,-1,sizeof(head)); //head数组初始化为-1
    memset(vis ,0,sizeof(vis));
    for(int i=0;i<=n;i++)
    {
        fa[i]=i;
        q[i].clear();
        id[i].clear();
    }
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n >> m;        //点的个数、询问的个数
        init();
        int x,y,z;
        for(int i=1;i<n;i++)  //n-1次加边
        {
            cin >> x >> y >> z;
            add(x,y,z);       //添加双向边
            add(y,x,z);
        }
        for(int i=1;i<=m;i++)     //一共m次询问,询问x,y的最近公共祖先
        {
            cin >> x >> y;        //x与y有关系

            /* 与x相关联的点是y,与y相关联的点是x */
            q[x].push_back(y); //在vector->q中, 将y加入x ,将x加入y (将x放入y中,将y放入x中)(q[x]是从0开始计数的,所以找的时候从[0~q[x].size)
            q[y].push_back(x);

            /* x,y的询问编号都是i */
            id[x].push_back(i);   //在vector->id中,将i加入x ,将i加入y (将第i条边的序号i放入x,y中)
            id[y].push_back(i);

            ans[i]=0x3f3f3f3f;    //每个询问最后的结果都是最大值
        }
        dfs(1);
        for(int i=1;i<=m;i++) //一共m次询问,每个询问输出一个两个点到最近公共祖先的最短距离
        {
            cout << ans[i] << endl;
        }
    }
    return 0;
}