Problem:
Meeting in a City
You are a teacher at Iazu High School is the Zuia Kingdom. There are $N$ cities and $N-1$ roads connecting them that allow you to move from one city to another by way of more than one road. Each of the roads allows bidirectional traffic and has a known length.
As a part of class activities, you are planning the following action assignment for your students. First, you come up with several themes commonly applicable to three different cities. Second, you assign each of the themes to a group of three students. Then, each student of a group is assigned to one of the three cities and conducts a survey on it. Finally, all students of the group get together in one of the $N$ cities and compile their results.
After a theme group has completed its survey, the three members move from the city on which they studied to the city for getting together. The longest distance they have to travel for getting together is defined as the cost of the theme. You want to select the meeting city so that the cost for each theme becomes minimum.
Given the number of cities, road information and $Q$ sets of three cities for each theme, make a program to work out the minimum cost for each theme.
Input
The input is given in the following format.
$N$ $Q$ 
$u_1$ $v_1$ $w_1$
$u_2$ $v_2$ $w_2$
$...$
$u_{N-1}$ $v_{N-1}$ $w_{N-1}$
$a_1$ $b_1$ $c_1$
$a_2$ $b_2$ $c_2$
$...$
$a_Q$ $b_Q$ $c_Q$
The first line provides the number of cities in the Zuia Kingdom $N$ ($3 \leq N \leq 100,000$) and the number of themes $Q$ ($1 \leq Q \leq 100,000$). Each of the subsequent $N-1$ lines provides the information regarding the $i$-th road $u_i,v_i,w_i$ ($ 1 \leq u_i < v_i \leq N, 1 \leq w_i \leq 10,000$), indicating that the road connects cities $u_i$ and $v_i$, and the road distance between the two is $w_i$. Each of the $Q$ lines that follows the above provides the three cities assigned to the $i$-th theme: $a_i,b_i,c_i$ ($1 \leq a_i < b_i < c_i \leq N$).
Output
For each theme, output the cost in one line.
Sample Input 1
5 4
1 2 3
2 3 4
2 4 2
4 5 3
1 3 4
1 4 5
1 2 3
2 4 5
Sample Output 1
4
5
4
3
In the first theme, traveling distance from City 3 (the student conducts survey) to City 2 (meeting venue) determines the cost 4. As no other meeting city can provide smaller cost, you should output 4. In the second theme, you can minimize the cost down to 5 by selecting City 2 or City 4 as the meeting venue.
Sample Input 2
5 3
1 2 1
2 3 1
3 4 1
4 5 1
1 2 3
1 3 5
1 2 4
Sample Output 2
1
2
2
Sample Input 3
15 15
1 2 45
2 3 81
1 4 29
1 5 2
5 6 25
4 7 84
7 8 56
4 9 2
4 10 37
7 11 39
1 12 11
11 13 6
3 14 68
2 15 16
10 13 14
13 14 15
2 14 15
7 12 15
10 14 15
9 10 15
9 14 15
8 13 15
5 6 13
11 13 15
12 13 14
2 3 10
5 13 15
10 11 14
6 8 11
Sample Output 3
194
194
97
90
149
66
149
140
129
129
194
111
129
194
140

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define int long long
struct SEG{
private:
    int n;
    vector<int> node;
public:
    SEG(int N){
        n = 1;
        while(n < N) n *= 2;
        node.resize(2*n-1);
    }
    void update(int i, int x){
        i += n-1;
        node[i] = x;
        while(i){
            i = (i-1)/2;
            node[i] = node[2*i+1]+node[2*i+2];
        }
    }
    int f(int a, int b, int k = 0, int l = 0, int r = -1){
        if(r < 0) r = n;
        if(a <= l && r <= b) return node[k];
        if(b <= l || r <= a) return 0;
        return f(a,b,2*k+1,l,(l+r)/2)+f(a,b,2*k+2,(l+r)/2,r);
    }
};
signed main(){
    int N,Q;
    cin>>N>>Q;
    vector<vector<pair<int,int>>> G(N);
    for(int i=0;i<N-1;i++){
        int a,b,c;
        cin>>a>>b>>c;
        a--;
        b--;
        G[a].push_back({b,c});
        G[b].push_back({a,c});
    }
    int n = 17;
    vector<vector<int>> P(n,vector<int>(N,-1));
    vector<vector<int>> D(n,vector<int>(N));
    vector<int> dist(N,1e18), dt(N);
    {
        queue<int> q;
        q.push(0);
        dist[0] = 0;
        while(!q.empty()){
            int pos = q.front();
            q.pop();
            for(auto [x,w]:G[pos])if(dist[x] >= 1e17){
                dist[x] = dist[pos] + w;
                dt[x] = dt[pos] + 1;
                q.push(x);
            }
        }
        for(int i=0;i<N;i++)for(auto [x,w]:G[i])if(dist[x] < dist[i]){
            P[0][i] = x;
            D[0][i] = w;
        }
    }
    for(int i=1;i<n;i++)for(int j=0;j<N;j++)if(P[i-1][j] != -1){
        P[i][j] = P[i-1][P[i-1][j]];
        D[i][j] = D[i-1][j]+D[i-1][P[i-1][j]];
    }
    auto lca = [&](int a, int b) -> int {
        if(dt[a] < dt[b]) swap(a,b);
        int k = dt[a]-dt[b];
        for(int i=0;i<n;i++)if(k&(1<<i)) a = P[i][a];
        if(a == b) return a;
        for(int i=n-1;i>=0;i--)if(P[i][a] != -1 && P[i][b] != -1 && P[i][a] != P[i][b]){
            a = P[i][a];
            b = P[i][b];
        }
        return P[0][a];
    };
    auto d = [&](int a, int b) -> int {
        int p = lca(a,b);
        return dist[a]+dist[b]-2*dist[p];
    };
    while(Q--){
        int a,b,c;
        cin>>a>>b>>c;
        a--;
        b--;
        c--;
        if(dt[a] < dt[b]) swap(a,b);
        if(dt[b] < dt[c]) swap(b,c);
        if(dt[a] < dt[b]) swap(a,b);
        if(dt[b] < dt[c]) swap(b,c);
        int t = 0;
        {
            int aa = lca(a,b);
            int bb = lca(b,c);
            int cc = lca(c,a);
            if(dt[aa] == max({dt[aa],dt[bb],dt[cc]})) t = aa;
            if(dt[bb] == max({dt[aa],dt[bb],dt[cc]})) t = bb;
            if(dt[cc] == max({dt[aa],dt[bb],dt[cc]})) t = cc;
        }
        if(d(a,t) < d(b,t)) swap(a,b);
        if(d(b,t) < d(c,t)) swap(b,c);
        if(d(a,t) < d(b,t)) swap(a,b);
        if(d(b,t) < d(c,t)) swap(b,c);
        // t -> a
        int s = lca(t,a);
        int aa = d(a,s), bb = d(s,t);
        int ans = d(a,t);
        int bt = (aa+bb+d(b,t)+1)/2;
        {
            int now = 0;
            int j = a;
            for(int i=n-1;i>=0;i--)if(now+D[i][j] <= bt && dt[j]-(1<<i) >= dt[s] && P[i][j] != -1){
                now += D[i][j];
                j = P[i][j];
            }
            ans = min(ans,max({d(a,j),d(b,j)}));
            if(j == s && t != s){
                int k = dt[t]-dt[s]-1;
                int wt = t;
                for(int i=0;i<n;i++)if(k&(1<<i)) wt = P[i][wt];
                j = wt;
            }
            else if(j != 0) j = P[0][j];
            ans = min(ans,max({d(a,j),d(b,j)}));
        }
        bt = aa+bb-(aa+bb+d(b,t)+1)/2;
        {
            int now = 0;
            int j = t;
            for(int i=n-1;i>=0;i--)if(now+D[i][j] <= bt && dt[j]-(1<<i) >= dt[s] && P[i][j] != -1){
                now += D[i][j];
                j = P[i][j];
            }
            ans = min(ans,max({d(a,j),d(b,j)}));
            if(j == s && t != s){
                int k = dt[a]-dt[s]-1;
                int wt = a;
                for(int i=0;i<n;i++)if(k&(1<<i)) wt = P[i][wt];
                j = wt;
            }
            else if(j != 0) j = P[0][j];
            ans = min(ans,max({d(a,j),d(b,j)}));
        }
        cout<<ans<<endl;
    }
}
accuracy: 1
time_ms: 520
memory_kb: 38484
final_rank: 12

code_snippet: #include <bits/stdc++.h>

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rep2(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define rrep(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define rrep2(i, a, b) for (int i = (int)(b) - 1; i >= (int)(a); --i)

#define all(v) begin(v), end(v)
#define rall(v) rbegin(v), rend(v)

using namespace std;

using ll = long long;
using PLL = pair<ll, ll>;

template<class T, class U> bool chmin(T& a, const U& b) { return a > b ? a = b, true : false; }
template<class T, class U> bool chmax(T& a, const U& b) { return a < b ? a = b, true : false; }

struct edge {
    int to;
    ll cost;
    edge(int t, ll c) : to(t), cost(c) {}
};

using Graph = vector<vector<edge>>;

class TreeQuery {
    int n;
    Graph G;

    vector<ll> dep, rank;
    vector<vector<int>> par;

public:
    TreeQuery(Graph H) : n(H.size()), G(H) {
        dep.assign(n, 0);
        rank.assign(n, 0);
        par.assign(20, vector<int>(n, -1));
        auto dfs = [&](auto&& self, int v, int p) -> void {
            par[0][v] = p;
            for (auto e : G[v]) if (e.to != p) {
                dep[e.to] = dep[v] + e.cost;
                rank[e.to] = rank[v] + 1;
                self(self, e.to, v);
            }
        };
        dfs(dfs, 0, -1);
        rep (i, 19) rep (j, n) par[i + 1][j] = par[i][j] == -1 ? -1 : par[i][par[i][j]];
    }
    int kth_ancestor(int a, int k) const {
        rep (i, 20) if (k >> i & 1) a = par[i][a];
        return a;
    }
    int lca(int a, int b) const {
        if (rank[a] > rank[b]) swap(a, b);
        b = kth_ancestor(b, rank[b] - rank[a]);
        if (a == b) return a;
        rrep (i, 20) {
            if (par[i][a] != par[i][b]) {
                a = par[i][a];
                b = par[i][b];
            }
        }
        return par[0][a];
    }
    int kth_next(int a, int b, int k) const {
        int l = lca(a, b);
        if (rank[a] - rank[l] >= k) return kth_ancestor(a, k);
        return kth_ancestor(b, (rank[a] + rank[b] - 2 * rank[l]) - k);
    }
    ll dist(int a, int b) const { return dep[a] + dep[b] - 2 * dep[lca(a, b)]; }
    int dist_r(int a, int b) const { return rank[a] + rank[b] - 2 * rank[lca(a, b)]; }
};

int main() {
    int N, Q; scanf("%d%d", &N, &Q);
    Graph G(N);
    rep (_, N - 1) {
        int a, b;
        ll c;
        scanf("%d%d%lld", &a, &b, &c);
        --a; --b;
        G[a].emplace_back(b, c);
        G[b].emplace_back(a, c);
    }
    TreeQuery T(G);
    rep (_, Q) {
        int a, b, c; scanf("%d%d%d", &a, &b, &c);
        --a; --b; --c;
        int x = T.lca(a, b) ^ T.lca(b, c) ^ T.lca(c, a);
        ll da = T.dist(a, x), db = T.dist(b, x), dc = T.dist(c, x);
        {
            ll m = max({da, db, dc});
            if (m == da) ;
            else if (m == db) {
                swap(a, b);
                swap(da, db);
            }
            else {
                swap(a, c);
                swap(da, dc);
            }
        }
        ll dbc = max(db, dc);
        auto calc = [&](int v) -> ll {
            return max(T.dist(a, v), T.dist(x, v) + dbc);
        };
        int ok = 0, ng = T.dist_r(x, a) + 1;
        while (ng - ok > 1) {
            int mid = (ok + ng) / 2;
            int v = T.kth_next(x, a, mid);
            int nv = T.kth_next(x, a, mid - 1);
            if (calc(v) <= calc(nv)) ok = mid;
            else ng = mid;
        }
        int v = T.kth_next(x, a, ok);
        printf("%lld\n", calc(v));
    }
}
accuracy: 1
time_ms: 750
memory_kb: 41288
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ld=long double;
#define fi first
#define se second
#define i128 __int128_t
#define all(x) x.begin(),x.end()
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define si(a) (long)(a.size())
template<typename T>bool chmin(T&a,T b){return b<a?(a=b,1):0;}
template<typename T>bool chmax(T&a,T b){return b>a?(a=b,1):0;}
const int INF=1e9+100;
const long INFL=3e18+100;
struct _ {
   _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;



struct LCA {
    int N;
    vector<vector<pair<int,int>>> G;
    vector<vector<int>> P;
    vector<int> dep,W;
    LCA(vector<vector<pair<int,int>>> G_, int root = 0) : N(si(G_)), G(G_), dep(si(G_)), W(si(G_)){
        int lg = 0;
        while ((1 << lg) + 1 < N) lg++;
        P.assign(lg + 1, vector<int>(N));

        dfs(root, -1, 0, 0);
        for (int k = 1; k < si(P); k++) {
            rep(i, N) {
                if (P[k - 1][i] == -1)
                    P[k][i] = -1;
                else
                    P[k][i] = P[k - 1][P[k - 1][i]];
            }
        }
    }
    void dfs(int u, int p, int d, int w) {
        W[u]=w;
        dep[u] = d;
        P[0][u] = p;
        for (auto [v,c] : G[u])
            if (v != p) dfs(v, u, d + 1, w+c);
    }
    int lca(int u, int v) {
        if (dep[u] > dep[v]) swap(u, v);
        rep(k, si(P)) if ((dep[v] - dep[u]) >> k & 1) v = P[k][v];
        if (u == v) return u;
        for (int k = si(P); k--;)
            if (P[k][u] != P[k][v]) {
                u = P[k][u];
                v = P[k][v];
            }
        return P[0][u];
    }
    
    int hist(int u, int v) {
        int w = lca(u, v);
        return dep[u] + dep[v] - 2 * dep[w];
    }

    int dist(int u, int v) {
        int w = lca(u, v);
        return W[u] + W[v] - 2 * W[w];
    }
};


int main(){
    int N,Q;
    cin>>N>>Q;
    vector<vector<pair<int,int>>> G(N);
    rep(i,N-1){
        int u,v,w;cin>>u>>v>>w;
        u--;v--;
        G[u].push_back({v,w});
        G[v].push_back({u,w});
    }
    LCA lca(G);
    
    vector<vector<pair<int,int>>> A(N);
    auto f=[&](int u, int v, int id)->void {
        int l=lca.lca(u,v);
        if(lca.dist(u,l)<lca.dist(v,l)) swap(u,v);
        A[u].push_back({lca.dist(u,v),id});

        return ;
    };
    rep(i,Q){
        int a,b,c;
        cin>>a>>b>>c;
        a--;b--;c--;
        f(a,b,i);f(a,c,i);f(b,c,i);
    }
    vector<int> ans(Q,0);
    vector<int> now={-1};
    vector<int> nov;
    auto dfs=[&](auto dfs, int v, int p, int w)->void {
        now.push_back(w);
        nov.push_back(v);
        for(auto [x, qi]: A[v]){
            int id=si(nov)-(now.end()-lower_bound(all(now), w-x/2));
            int mi=1e9;
            rep(z,2){
                if(id<0) continue;
                int d=lca.dist(v, nov[id]);
                chmin(mi, max(d, x-d));
                id--;
            }
            chmax(ans[qi], mi);

        }
        for(auto [e,c]: G[v]){
            if(e==p) continue;
            dfs(dfs, e, v, w+c);
        }
        nov.pop_back();
        now.pop_back();
    };
    dfs(dfs, 0, -1, 0);

    rep(i,Q)cout<<ans[i]<<"\n";
}
accuracy: 1
time_ms: 280
memory_kb: 53964
final_rank: 14

code_snippet: // AOJ #391
// Gathering 2025.2.8

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

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {  // 整数の入力
	int n = 0, c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) { // 整数の表示（出力）
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

const int NMAX = 100000;
int N, Q;
 
vector<pair<int,int>> adj[NMAX+1];
 
int depth[NMAX+1];
ll distArr[NMAX+1];
 
int LOGN;
int parent[18][NMAX+1];
 
void computeTreeData(int root = 1) {
    memset(depth, 0, sizeof(depth));
    for (int i=1; i<=N; i++){
        distArr[i] = 0;
        parent[0][i] = 0;
    }
    vector<int> st;
    st.push_back(root);
    depth[root] = 0;
    distArr[root] = 0;
    while(!st.empty()){
        int u = st.back();
        st.pop_back();
        for(auto &edge : adj[u]){
            int v = edge.first;
            int w = edge.second;
            if(v == parent[0][u]) continue;
            parent[0][v] = u;
            depth[v] = depth[u] + 1;
            distArr[v] = distArr[u] + w;
            st.push_back(v);
        }
    }
}
 
void computeParents(){
    LOGN = 0;
    while((1 << LOGN) <= N) LOGN++;
    for (int i = 1; i < LOGN; i++){
        for (int v = 1; v <= N; v++){
            int par = parent[i-1][v];
            if(par == 0) parent[i][v] = 0;
            else parent[i][v] = parent[i-1][par];
        }
    }
}
 
int LCA(int u, int v) {
    if(depth[u] < depth[v]) swap(u,v);
    int d = depth[u] - depth[v];
    for(int i = 0; i < LOGN; i++){
        if(d & (1 << i)){
            u = parent[i][u];
        }
    }
    if(u == v) return u;
    for(int i = LOGN-1; i >= 0; i--){
        if(parent[i][u] != parent[i][v]){
            u = parent[i][u];
            v = parent[i][v];
        }
    }
    return parent[0][u];
}
 
ll getDist(int u, int v) {
    int l = LCA(u,v);
    return distArr[u] + distArr[v] - 2LL * distArr[l];
}
 
int kthAncestor(int u, int k) {
    for (int i = 0; i < LOGN; i++){
        if(k & (1 << i)){
            u = parent[i][u];
            if(u == 0) break;
        }
    }
    return u;
}
 
int getKthOnPath(int u, int v, int k) {
    int l = LCA(u,v);
    int d1 = depth[u] - depth[l];
    if(k <= d1){
        return kthAncestor(u, k);
    } else {
        int k2 = k - d1;
        int d2 = depth[v] - depth[l];
        return kthAncestor(v, d2 - k2);
    }
}
 
 
ll solveForTripleOnDiameter(int p, int q, int r) {
    int L = depth[p] + depth[q] - 2 * depth[LCA(p,q)];
    ll d_pq = getDist(p, q);
    auto F = [&](int k) -> ll {
        int x = getKthOnPath(p, q, k);
        ll A = getDist(p, x);
        ll B = d_pq - A;
        ll C = getDist(x, r);
        return max({A, B, C});
    };
    if(L == 0) return F(0);
    int lo = 0, hi = L;
    while(hi - lo > 3) {
        int m1 = lo + (hi - lo) / 3;
        int m2 = hi - (hi - lo) / 3;
        ll f1 = F(m1), f2 = F(m2);
        if(f1 > f2)
            lo = m1;
        else
            hi = m2;
    }
    ll ans = LLONG_MAX;
    for (int k = lo; k <= hi; k++){
        ans = min(ans, F(k));
    }
    return ans;
}
 
 
int main() {
    N = Cin(), Q = Cin();
    for (int i = 1; i <= N; i++){
        adj[i].clear();
    }
    for (int i = 1; i < N; i++){
        int u = Cin(), v = Cin(), w = Cin();
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }
 
    computeTreeData(1);
    computeParents();
 
    for (int i = 0; i < Q; i++){
        int a = Cin(), b = Cin(), c = Cin();
        ll dab = getDist(a, b);
        ll dac = getDist(a, c);
        ll dbc = getDist(b, c);
 
        int p, q, r;
        if(dab >= dac && dab >= dbc){
            p = a; q = b; r = c;
        } else if(dac >= dab && dac >= dbc){
            p = a; q = c; r = b;
        } else {
            p = b; q = c; r = a;
        }
 
        ll ans = solveForTripleOnDiameter(p, q, r);
        Cout(ans);
    }
    return 0;
}
accuracy: 1
time_ms: 910
memory_kb: 17572
final_rank: 6

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

struct virtualtree{
	long long n;
	vector<vector<long long>> g,p;
	vector<long long> o,d;
	long long cou = 0ll;
	virtualtree(vector<vector<long long>> g) : g(g), n(g.size()) {
		o.resize(n,-1ll);
		p.resize(n);
		d.resize(n);
		for(long long i = 0ll;i < n;i++){
			p[i].resize(20ll);
		}
		d[0ll] = 0ll;
		p[0ll][0ll] = 0ll;
		dfs(0ll);
		for(long long i = 1ll;i < 20ll;i++){
			for(long long j = 0ll;j < n;j++){
				p[j][i] = p[p[j][i - 1ll]][i - 1ll];
			}
		}
	}
	void dfs(long long x){
		o[x] = cou;
		cou++;
		for(long long i : g[x]){
			if(o[i] != -1ll){
				continue;
			}
			p[i][0ll] = x;
			d[i] = d[x] + 1ll;
			dfs(i);
		}
	}
	long long root(long long a,long long b){
		for(long long i = 0ll;i < 30ll;i++){
			if(b & (1ll << i)){
				a = p[a][i];
			}
		}
		return a;
	}
	long long lca(long long u,long long v){
		if(d[u] > d[v]){
			u = root(u,d[u] - d[v]);
		}
		if(d[v] > d[u]){
			v = root(v,d[v] - d[u]);
		}
		long long low = 0ll,high = n;
		while(low < high){
			long long mid = (low + high) / 2ll;
			if(root(u,mid) == root(v,mid)){
				high = mid;
			}else{
				low = mid + 1ll;
			}
		}
		return root(u,low);
	}
	long long dist(long long u,long long v){
		long long lc = lca(u,v);
		return d[u] + d[v] - d[lc] * 2ll;
	}
	vector<vector<pair<long long,long long>>> get(vector<long long> x){
		vector<vector<pair<long long,long long>>> res(x.size(),vector<pair<long long,long long>>());
		auto com = [&](long long a,long long b) -> bool {
			return o[a] < o[b];
		};
		map<long long,long long> t;
		set<long long> c;
		sort(x.begin(),x.end(),com);
		for(long long i = 0ll;i < (long long)x.size();i++){
			c.insert(x[i]);
			t[x[i]] = i;
		}
		x.push_back(x[0ll]);
		stack<long long> s;
		s.push(x[0ll]);
		for(long long i = 1ll;i < (long long)x.size();i++){
			long long lc = lca(x[i - 1ll],x[i]);
			if(!c.count(lc)){
				t[lc] = (long long)c.size();
				c.insert(lc);
				res.push_back({});
			}
			long long last = -1ll;
			while(!s.empty() && d[s.top()] >= d[lc]){
				long long it = s.top();
				s.pop();
				if(last != -1ll && last != it){
					res[t[it]].push_back({t[last],dist(it,last)});
					res[t[last]].push_back({t[it],dist(it,last)});
				}
				last = it;
			}
			if(last != -1ll && last != lc){
				res[t[last]].push_back({t[lc],dist(last,lc)});
				res[t[lc]].push_back({t[last],dist(last,lc)});
			}
			s.push(lc);
			s.push(x[i]);
		}
		return res;
	}
};
int main()
{
	long long n,Q;
	cin >> n >> Q;
	vector<vector<long long>> gh(n,vector<long long>());
	vector<vector<pair<long long,long long>>> g(n,vector<pair<long long,long long>>());
	for(long long i = 0ll;i < n - 1ll;i++){
		long long u,v,w;
		cin >> u >> v >> w;
		u--;v--;
		gh[u].push_back(v);
		gh[v].push_back(u);
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	virtualtree vt(gh);
	vector<long long> dist(n,-1ll);
	{
		queue<long long> q;
		q.push(0ll);
		dist[0ll] = 0ll;
		while(!q.empty()){
			long long it = q.front();
			q.pop();
			for(pair<long long,long long> i : g[it]){
				if(dist[i.first] != -1ll) continue;
				dist[i.first] = dist[it] + i.second;
				q.push(i.first);
			}
		}
	}
	auto dis = [&](long long u,long long v) -> long long {
		long long lc = vt.lca(u,v);
		return dist[u] + dist[v] - dist[lc] * 2ll;
	};
	for(long long cnt = 0ll;cnt < Q;cnt++){
		long long a,b,c;
		cin >> a >> b >> c;
		a--;b--;c--;
		if(dist[a] < dist[b]) swap(a,b);
		if(dist[a] < dist[c]) swap(a,c);
		long long it = max({dis(a,b),dis(a,c),dis(b,c)});
		long long t = it;
		it = (it + 1ll) / 2ll;
		long long low = 0ll,high = n;
		while(low < high){
			long long mid = (low + high) / 2ll;
			if(dist[a] - dist[vt.root(a,mid)] >= it){
				high = mid;
			}else{
				low = mid + 1ll;
			}
		}
		long long ans = dist[a] - dist[vt.root(a,low)]; 
		ans = min(ans,t - (dist[a] - dist[vt.root(a,low - 1)]));
		cout << ans << endl;
	}
}
accuracy: 1
time_ms: 1150
memory_kb: 52196
final_rank: 19

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

struct virtualtree{
	long long n;
	vector<vector<long long>> g,p;
	vector<long long> o,d;
	long long cou = 0ll;
	virtualtree(vector<vector<long long>> g) : g(g), n(g.size()) {
		o.resize(n,-1ll);
		p.resize(n);
		d.resize(n);
		for(long long i = 0ll;i < n;i++){
			p[i].resize(20ll);
		}
		d[0ll] = 0ll;
		p[0ll][0ll] = 0ll;
		dfs(0ll);
		for(long long i = 1ll;i < 20ll;i++){
			for(long long j = 0ll;j < n;j++){
				p[j][i] = p[p[j][i - 1ll]][i - 1ll];
			}
		}
	}
	void dfs(long long x){
		o[x] = cou;
		cou++;
		for(long long i : g[x]){
			if(o[i] != -1ll){
				continue;
			}
			p[i][0ll] = x;
			d[i] = d[x] + 1ll;
			dfs(i);
		}
	}
	long long root(long long a,long long b){
		for(long long i = 0ll;i < 30ll;i++){
			if(b & (1ll << i)){
				a = p[a][i];
			}
		}
		return a;
	}
	long long lca(long long u,long long v){
		if(d[u] > d[v]){
			u = root(u,d[u] - d[v]);
		}
		if(d[v] > d[u]){
			v = root(v,d[v] - d[u]);
		}
		long long low = 0ll,high = n;
		while(low < high){
			long long mid = (low + high) / 2ll;
			if(root(u,mid) == root(v,mid)){
				high = mid;
			}else{
				low = mid + 1ll;
			}
		}
		return root(u,low);
	}
	long long dist(long long u,long long v){
		long long lc = lca(u,v);
		return d[u] + d[v] - d[lc] * 2ll;
	}
	vector<vector<pair<long long,long long>>> get(vector<long long> x){
		vector<vector<pair<long long,long long>>> res(x.size(),vector<pair<long long,long long>>());
		auto com = [&](long long a,long long b) -> bool {
			return o[a] < o[b];
		};
		map<long long,long long> t;
		set<long long> c;
		sort(x.begin(),x.end(),com);
		for(long long i = 0ll;i < (long long)x.size();i++){
			c.insert(x[i]);
			t[x[i]] = i;
		}
		x.push_back(x[0ll]);
		stack<long long> s;
		s.push(x[0ll]);
		for(long long i = 1ll;i < (long long)x.size();i++){
			long long lc = lca(x[i - 1ll],x[i]);
			if(!c.count(lc)){
				t[lc] = (long long)c.size();
				c.insert(lc);
				res.push_back({});
			}
			long long last = -1ll;
			while(!s.empty() && d[s.top()] >= d[lc]){
				long long it = s.top();
				s.pop();
				if(last != -1ll && last != it){
					res[t[it]].push_back({t[last],dist(it,last)});
					res[t[last]].push_back({t[it],dist(it,last)});
				}
				last = it;
			}
			if(last != -1ll && last != lc){
				res[t[last]].push_back({t[lc],dist(last,lc)});
				res[t[lc]].push_back({t[last],dist(last,lc)});
			}
			s.push(lc);
			s.push(x[i]);
		}
		return res;
	}
};
int main()
{
	long long n,Q;
	cin >> n >> Q;
	vector<vector<long long>> gh(n,vector<long long>());
	vector<vector<pair<long long,long long>>> g(n,vector<pair<long long,long long>>());
	for(long long i = 0ll;i < n - 1ll;i++){
		long long u,v,w;
		cin >> u >> v >> w;
		u--;v--;
		gh[u].push_back(v);
		gh[v].push_back(u);
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	virtualtree vt(gh);
	vector<long long> dist(n,-1ll);
	{
		queue<long long> q;
		q.push(0ll);
		dist[0ll] = 0ll;
		while(!q.empty()){
			long long it = q.front();
			q.pop();
			for(pair<long long,long long> i : g[it]){
				if(dist[i.first] != -1ll) continue;
				dist[i.first] = dist[it] + i.second;
				q.push(i.first);
			}
		}
	}
	auto dis = [&](long long u,long long v) -> long long {
		long long lc = vt.lca(u,v);
		return dist[u] + dist[v] - dist[lc] * 2ll;
	};
	for(long long cnt = 0ll;cnt < Q;cnt++){
		if(n < 100000){
		long long a,b,c;
		cin >> a >> b >> c;
		a--;b--;c--;
		if(dist[a] < dist[b]) swap(a,b);
		if(dist[a] < dist[c]) swap(a,c);
		long long it = max({dis(a,b),dis(a,c),dis(b,c)});
		long long t = it;
		it = (it + 1ll) / 2ll;
		long long low = 0ll,high = n;
		while(low < high){
			long long mid = (low + high) / 2ll;
			if(dis(a,vt.root(a,mid)) >= it){
				high = mid;
			}else{
				low = mid + 1ll;
			}
		}
		long long ans = dis(a,vt.root(a,low)); 
		ans = min(ans,t - dis(a,vt.root(a,low - 1ll)));
		cout << ans << endl;
		}
	}
}
accuracy: 0.625
time_ms: 80
memory_kb: 52392
final_rank: 20

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

struct lca_tree {
  int n, lg;
  vector<vector<int>> to;
  vector<vector<long long>> co;
  vector<int> dep;
  vector<long long> cost;
  vector<vector<int>> dest;
  lca_tree(int n) : n(n), to(n), co(n), dep(n), cost(n) {
    lg = 0;
    while((1<<lg) < n) lg++;
    dest = vector(lg+1, vector<int>(n+1, n));
  }
  void add_edge(int a, int b, long long c) {
    to[a].push_back(b); co[a].push_back(c);
    to[b].push_back(a); co[b].push_back(c);
  }
  void dfs(int v, int p) {
    for(int i = 0; i < int(to[v].size()); i++) {
      int u = to[v][i];
      if(u == p) continue;
      dep[u] = dep[v]+1;
      cost[u] = cost[v]+co[v][i];
      dest[0][u] = v;
      dfs(u, v);
    }
  }
  void build() {
    dfs(0, n);
    for(int k = 0; k < lg; k++) {
      for(int v = 0; v < n; v++) {
        dest[k+1][v] = dest[k][dest[k][v]];
      }
    }
  }
  // LCA
  int up(int v, int d) {
    for(int k = 0; k <= lg; k++) {
      if((d>>k)&1) v = dest[k][v];
    }
    return v;
  }
  int lca(int a, int b) {
    if(dep[a] > dep[b]) swap(a, b);
    b = up(b, dep[b]-dep[a]);
    if(a == b) return a;
    for(int k = lg; k >= 0; k--) {
      if(dest[k][a] != dest[k][b]) {
        a = dest[k][a], b = dest[k][b];
      }
    }
    return dest[0][a];
  }
  int length(int a, int b) {
    int c = lca(a, b);
    return dep[a]+dep[b]-2*dep[c];
  }
  long long dist(int a, int b) {
    int c = lca(a, b);
    return cost[a]+cost[b]-2*cost[c];
  }
};

int main() {
  int N, Q;
  cin >> N >> Q;
  lca_tree G(N);
  for(int i = 0; i < N-1; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    G.add_edge(u-1, v-1, w);
  }
  G.build();
  auto f = [&](int x, int y) -> long long {
    int z = G.lca(x, y);
    if(G.dist(x, z) < G.dist(y, z)) swap(x, y);
    int ok = 0, ng = G.length(x, z);
    while(ok+1 < ng) {
      int k = (ok+ng)/2;
      int w = G.up(x, k);
      if(G.dist(x, w) < G.dist(y, w)) ok = k;
      else ng = k;
    }
    int wo = G.up(x, ok), wn = G.up(x, ng);
    return min(max(G.dist(x, wo), G.dist(y, wo)), max(G.dist(x, wn), G.dist(y, wn)));
  };
  for(int q = 0; q < Q; q++) {
    int a, b, c;
    cin >> a >> b >> c;
    a--, b--, c--;
    cout << max({f(a, b), f(b, c), f(c, a)}) << endl;
  }
}
accuracy: 1
time_ms: 1120
memory_kb: 29840
final_rank: 15

code_snippet: #include <bits/stdc++.h>

struct LCA {
    static constexpr int ROOT = 0;
    static constexpr int LOG = 20;
    std::vector<std::vector<int>> parent;
    std::vector<int> depth;
    std::vector<int> depth_with_weight;
    LCA(const std::vector<std::vector<std::pair<int, int>>>& graph) {
        int n = graph.size();
        parent.assign(n, std::vector<int>(LOG + 1));
        depth.assign(n, 0);
        depth_with_weight.assign(n, 0);
        auto dfs = [&](auto self, int u, int p) -> void {
            parent[u][0] = p;
            for (auto [v, w]: graph[u]) {
                if (v == p) continue;
                depth[v] = depth[u] + 1;
                depth_with_weight[v] = depth_with_weight[u] + w;
                self(self, v, u);
            }
        };
        dfs(dfs, ROOT, ROOT);
        for (int i = 0; i < LOG; i++) {
            for (int j = 0; j < n; j++) {
                parent[j][i + 1] = parent[parent[j][i]][i];
            }
        }
    }
    int lca(int lhs, int rhs) {
        if (depth[lhs] < depth[rhs]) std::swap(lhs, rhs);
        int diff = depth[lhs] - depth[rhs];
        // std::cerr << "diff = " << diff << '\n';
        for (int i = 0; i < LOG; i++) {
            if (diff & (1 << i)) {
                lhs = parent[lhs][i];
            }
        }
        assert(depth[lhs] == depth[rhs]);
        if (lhs == rhs) return lhs;
        for (int i = LOG; i >= 0; i--) {
            if (parent[lhs][i] != parent[rhs][i]) {
                lhs = parent[lhs][i];
                rhs = parent[rhs][i];
            }
        }
        assert(lhs != rhs);
        assert(parent[lhs][0] == parent[rhs][0]);
        return parent[lhs][0];
    }
    int dist(int u, int v) {
        return dist(u, v, lca(u, v));
    }
    int dist(int u, int v, int w) {
        return depth_with_weight[u] + depth_with_weight[v] - 2 * depth_with_weight[w];
    }
    int ancester(int u, int k) {
        for (int i = LOG; i >= 0; i--) {
            if (depth_with_weight[u] - depth_with_weight[parent[u][i]] <= k) {
                k -= depth_with_weight[u] - depth_with_weight[parent[u][i]];
                u = parent[u][i];
            }
        }
        assert(k >= 0);
        return u;
    }
};

int main() {
    int n, q;
    std::cin >> n >> q;
    std::vector<std::vector<std::pair<int, int>>> graph(n);
    for (int i = 0; i + 1 < n; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        u--; v--;
        graph[u].emplace_back(v, w);
        graph[v].emplace_back(u, w);
    }
    LCA lca(graph);

    auto query = [&](int u, int v) {
        int w = lca.lca(u, v);
        if (u == w || v == w) {
            if (v == w) std::swap(u, v);
            // root -> u -> v
            int ok = lca.dist(u, v, w);
            int ng = 0;
            while (ok - ng > 1) {
                int key = (ok + ng) / 2;
                int vv = lca.ancester(v, key);
                if (lca.dist(u, vv, w) <= key) {
                    ok = key;
                } else {
                    ng = key;
                }
            }
            return ok;
        } else {
            int u_dist = lca.dist(u, w, w);
            int v_dist = lca.dist(v, w, w);
            if (u_dist > v_dist) {
                std::swap(u_dist, v_dist);
                std::swap(u, v);
            }
            // root -> w -> u
            //           -> ... -> v
            int ok = v_dist;
            int ng = u_dist;
            while (ok - ng > 1) {
                int key = (ok + ng) / 2;
                int vv = lca.ancester(v, key);
                if (lca.dist(u, vv, w) <= key) {
                    ok = key;
                } else {
                    ng = key;
                }
            }
            return ok;
        }
    };

    while (q--) {
        int a, b, c;
        std::cin >> a >> b >> c;
        a--; b--; c--;
        int ans = std::max({query(a, b), query(b, c), query(a, c)});
        std::cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 950
memory_kb: 28772
final_rank: 13

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 0391.cc: Meeting in a City
 */

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<functional>
#include<utility>
 
using namespace std;

/* constant */

const int MAX_N = 100000;
const int BN = 17;
const int INF = 1 << 30;
const long long LINF = 1LL << 60;

/* typedef */

typedef long long ll;
typedef queue<int> qi;
typedef pair<int,int> pii;
typedef vector<pii> vpii;

/* global variables */

vpii nbrs[MAX_N];
int ps[MAX_N][BN], ds[MAX_N], dws[MAX_N], cis[MAX_N];

/* subroutines */

int ancestor(int u, int d) {
  for (int i = BN - 1; i >= 0; i--)
    if ((d >> i) & 1) u = ps[u][i];
  return u;
}

int find_lca(int u, int v) {
  if (ds[u] > ds[v]) swap(u, v);

  v = ancestor(v, ds[v] - ds[u]);
  if (u == v) return u;

  for(int i = BN - 1; i >= 0; i--)
    if (ps[u][i] != ps[v][i])
      u = ps[u][i], v = ps[v][i];

  return ps[u][0];
}

int pathd(int u, int v) {
  int t = find_lca(u, v);
  return ds[u] + ds[v] - ds[t] * 2;
}

int pathw(int u, int v) {
  int t = find_lca(u, v);
  return dws[u] + dws[v] - dws[t] * 2;
}

int check(int a, int b, int c, int t, int x) { // t = lca(a, b)
  int lda = ds[a] + ds[b] - ds[t] * 2;
  int s = (ds[a] - ds[t] >= x) ? ancestor(a, x) : ancestor(b, lda - x);
  return max(pathw(a, s), max(pathw(b, s), pathw(c, s)));
}

/* main */

int main() {
  int n, qn;
  scanf("%d%d", &n, &qn);

  for (int i = 1; i < n; i++) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    u--, v--;
    nbrs[u].push_back(pii(v, w));
    nbrs[v].push_back(pii(u, w));
  }

  ps[0][0] = -1, dws[0] = 0, ds[0] = 0;
  for (int u = 0; u >= 0;) {
    vpii &nbru = nbrs[u];
    int up = ps[u][0];

    if (cis[u] < nbru.size()) {
      pii vw = nbru[cis[u]++];
      int v = vw.first, w = vw.second;
      if (v != up) {
	ps[v][0] = u, dws[v] = dws[u] + w, ds[v] = ds[u] + 1;
	u = v;
      }
    }
    else {
      u = up;
    }
  }

  for (int i = 0; i < BN - 1; i++)
    for (int u = 0; u < n; u++)
      ps[u][i + 1] = (ps[u][i] >= 0) ? ps[ps[u][i]][i] : -1;

  while (qn--) {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    a--, b--, c--;

    int dab = pathw(a, b);
    int dbc = pathw(b, c);
    int dca = pathw(c, a);

    if (dbc >= dab && dbc >= dca) swap(a, c), swap(dab, dbc);
    else if (dca >= dab && dca >= dbc) swap(b, c), swap(dab, dca);
    //printf("%d,%d,%d -> ab=%d,bc=%d,ca=%d\n", a, b, c, dab, dbc, dca);

    int t = find_lca(a, b);
    int x0 = 0, x1 = ds[a] + ds[b] - ds[t] * 2;
    while (x0 + 2 < x1) {
      int xx0 = (x0 * 2 + x1) / 3;
      int xx1 = (x0 + x1 * 2) / 3;
      int c0 = check(a, b, c, t, xx0);
      int c1 = check(a, b, c, t, xx1);
      if (c0 > c1) x0 = xx0;
      else x1 = xx1;
    }

    int minc = INF;
    for (int x = x0; x <= x1; x++)
      minc = min(minc, check(a, b, c, t, x));

    printf("%d\n", minc);
  }
  return 0;
}
accuracy: 1
time_ms: 1040
memory_kb: 17292
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int LOG = 18;
struct lowest_common_ancestor{
  vector<int> d;
  vector<vector<int>> p;
  lowest_common_ancestor(){
  }
  lowest_common_ancestor(vector<int> &P, vector<vector<int>> &c){
    int N = P.size();
    d = vector<int>(N, 0);
    queue<int> Q;
    Q.push(0);
    while (!Q.empty()){
      int v = Q.front();
      Q.pop();
      for (int w : c[v]){
        d[w] = d[v] + 1;
        Q.push(w);
      }
    }
    p = vector<vector<int>>(LOG, vector<int>(N, -1));
    for (int i = 0; i < N; i++){
      p[0][i] = P[i];
    }
    for (int i = 1; i < LOG; i++){
      for (int j = 0; j < N; j++){
        if (p[i - 1][j] != -1){
          p[i][j] = p[i - 1][p[i - 1][j]];
        }
      }
    }
  }
  int la(int u, int x){
    for (int k = 0; k < LOG; k++){
      if (x >> k & 1){
        u = p[k][u];
        if (u == -1){
          return -1;
        }
      }
    }
    return u;
  }
  int lca(int u, int v){
    if (d[u] > d[v]){
      swap(u, v);
    }
    v = la(v, d[v] - d[u]);
    if (u == v){
      return u;
    }
    for (int k = LOG - 1; k >= 0; k--){
      if (p[k][u] != p[k][v]){
        u = p[k][u];
        v = p[k][v];
      }
    }
    return p[0][u];
  }
  int dist(int u, int v){
    return d[u] + d[v] - 2 * d[lca(u, v)];
  }
};
struct weighted_tree_distance{
  //�d�݂��؂�2���_�Ԃ̋��� O(logN)
  lowest_common_ancestor T;
  vector<long long> s;
  weighted_tree_distance(vector<int> &p, vector<vector<pair<int, int>>> &c){
    int N = p.size();
    s = vector<long long>(N, 0);
    vector<vector<int>> c2(N);
    queue<int> Q;
    Q.push(0);
    while (!Q.empty()){
      int v = Q.front();
      Q.pop();
      for (auto P : c[v]){
        int d = P.first;
        int w = P.second;
        s[w] = s[v] + d;
        c2[v].push_back(w);
        Q.push(w);
      }
    }
    T = lowest_common_ancestor(p, c2);
  }
  int la(int u, int x){
    return T.la(u, x);
  }
  int lca(int u, int v){
    return T.lca(u, v);
  }
  long long dist(int u, int v){
    return s[u] + s[v] - 2 * s[T.lca(u, v)];
  }
  int path_point(int u, int v, int x){
    //u->v�p�X��u���狗��x
    int w = T.lca(u, v);
    int d = T.dist(u, w);
    if (x <= d){
      return T.la(u, x);
    } else {
      return T.la(v, T.dist(u, v) - x);
    }
  }
};
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int N, Q;
  cin >> N >> Q;
  vector<vector<int>> E1(N);
  vector<vector<pair<int, int>>> E2(N);
  for (int i = 0; i < N - 1; i++){
    int u, v, w;
    cin >> u >> v >> w;
    u--;
    v--;
    E1[u].push_back(v);
    E1[v].push_back(u);
    E2[u].push_back(make_pair(w, v));
    E2[v].push_back(make_pair(w, u));
  }
  vector<int> p(N, -1);
  vector<vector<pair<int, int>>> ch(N);
  queue<int> q;
  q.push(0);
  while (!q.empty()){
    int v = q.front();
    q.pop();
    for (auto P : E2[v]){
      int d = P.first;
      int w = P.second;
      if (w != p[v]){
        p[w] = v;
        ch[v].push_back(make_pair(d, w));
        q.push(w);
      }
    }
  }
  weighted_tree_distance T(p, ch);
  for (int i = 0; i < Q; i++){
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    c--;
    int x;
    int ab = T.lca(a, b);
    int bc = T.lca(b, c);
    int ca = T.lca(c, a);
    if (ab == a && ca == a){
      x = bc;
    } else if (bc == b && ab == b){
      x = ca;
    } else if (ca == c && bc == c){
      x = ab;
    } else {
      int abc = T.lca(ab, c);
      if (abc != ab){
        x = ab;
      } else if (abc != bc){
        x = bc;
      } else {
        x = ca;
      }
    }
    long long da = T.dist(x, a);
    long long db = T.dist(x, b);
    long long dc = T.dist(x, c);
    long long ans = max({da, db, dc});
    int A = a, B = b, C = c;
    if (da < db){
      swap(A, B);
      swap(da, db);
    }
    if (max(da, db) < dc){
      swap(A, C);
      swap(da, dc);
    }
    long long p = da;
    long long q = max(db, dc);
    //cout << "x = " << x << endl;
    //cout << "p = " << p << ", q = " << q << endl;
    long long t = (p - q) / 2;
    //cout << "t = " << t << endl;
    int dist = T.T.dist(A, x);
    //cout << "x = " << x << ", A = " << A << endl;
    ans = min(ans, max(T.dist(A, B), T.dist(A, C)));
    int L = 0;
    int R = dist;
    while (R - L > 1){
      int mid = (L + R) / 2;
      int v = T.path_point(x, A, mid);
      //cout << "mid = " << mid << ", v = " << v << endl;
      long long t2 = T.dist(x, v);
      //cout << "mid = " << mid << ", t2 = " << t2 << endl;
      if (t2 > t){
        R = mid;
      } else {
        L = mid;
      }
    }
    for (int j = L; j <= R; j++){
      int v = T.path_point(x, A, j);
      long long t2 = T.dist(x, v);
      long long dmax = max(p - t2, q + t2);
      ans = min(ans, dmax);
    }
    cout << ans << "\n";
  }
}
accuracy: 1
time_ms: 480
memory_kb: 33700
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n)  for(long long i=0;i<(long long)(n);i++)
#define REP(i,k,n) for(long long i=k;i<(long long)(n);i++)
#define pb emplace_back
#define lb(v,k) (lower_bound(all(v),(k))-v.begin())
#define ub(v,k) (upper_bound(all(v),(k))-v.begin())
#define fi first
#define se second
#define pi M_PI
#define PQ(T) priority_queue<T>
#define SPQ(T) priority_queue<T,vector<T>,greater<T>>
#define dame(a) {out(a);return 0;}
#define decimal cout<<fixed<<setprecision(15);
#define all(a) a.begin(),a.end()
#define rsort(a) {sort(all(a));reverse(all(a));}
#define dupli(a) {sort(all(a));a.erase(unique(all(a)),a.end());}
#define popcnt __builtin_popcountll
typedef long long ll;
typedef pair<ll,ll> P;
typedef tuple<ll,ll,ll> PP;
typedef tuple<ll,ll,ll,ll> PPP;
using vi=vector<ll>;
using vvi=vector<vi>;
using vvvi=vector<vvi>;
using vvvvi=vector<vvvi>;
using vp=vector<P>;
using vvp=vector<vp>;
using vb=vector<bool>;
using vvb=vector<vb>;
const ll inf=1001001001001001001;
const ll INF=1001001001;
const ll mod=998244353;
const double eps=1e-10;
template<class T> bool chmin(T&a,T b){if(a>b){a=b;return true;}return false;}
template<class T> bool chmax(T&a,T b){if(a<b){a=b;return true;}return false;}
template<class T> void out(T a){cout<<a<<'\n';}
template<class T> void outp(T a){cout<<'('<<a.fi<<','<<a.se<<')'<<'\n';}
template<class T> void outvp(T v){rep(i,v.size())cout<<'('<<v[i].fi<<','<<v[i].se<<')';cout<<'\n';}
template<class T> void outvvp(T v){rep(i,v.size())outvp(v[i]);}
template<class T> void outv(T v){rep(i,v.size()){if(i)cout<<' ';cout<<v[i];}cout<<'\n';}
template<class T> void outvv(T v){rep(i,v.size())outv(v[i]);}
template<class T> bool isin(T x,T l,T r){return (l)<=(x)&&(x)<=(r);}
template<class T> void yesno(T b){if(b)out("yes");else out("no");}
template<class T> void YesNo(T b){if(b)out("Yes");else out("No");}
template<class T> void YESNO(T b){if(b)out("YES");else out("NO");}
template<class T> void outset(T s){auto itr=s.begin();while(itr!=s.end()){if(itr!=s.begin())cout<<' ';cout<<*itr;itr++;}cout<<'\n';}
void outs(ll a,ll b){if(a>=inf-100)out(b);else out(a);}
ll gcd(ll a,ll b){if(b==0)return a;return gcd(b,a%b);}
ll modpow(ll a,ll b){ll res=1;a%=mod;while(b){if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}


int main(){
    ll n,q;cin>>n>>q;
    vvp g(n);
    rep(i,n-1){
        ll a,b,c;cin>>a>>b>>c;a--;b--;
        g[a].pb(b,c);g[b].pb(a,c);
    }
    vi par(n),dep(n),dep2(n);
    function<void(ll,ll,ll,ll)> dfs=[&](ll i,ll p,ll d,ll d2){
        par[i]=p;dep[i]=d;dep2[i]=d2;
        for(auto x:g[i])if(x.fi!=p)dfs(x.fi,i,d+x.se,d2+1);
    };dfs(0,-1,0,0);
    vvi table(n,vi(20,-1));
    rep(i,n)table[i][0]=par[i];
    rep(i,19)rep(j,n)if(table[j][i]!=-1)table[j][i+1]=table[table[j][i]][i];
    auto lca=[&](ll a,ll b){
        if(dep2[a]>dep2[b])swap(a,b);
        ll dif=dep2[b]-dep2[a];
        rep(i,20)if(dif>>i&1)b=table[b][i];
        if(a==b)return a;
        for(int i=19;i>=0;i--)if(table[a][i]!=table[b][i]){
            a=table[a][i];b=table[b][i];
        }
        return par[a];
    };
    auto dis=[&](ll a,ll b){
        return dep[a]+dep[b]-dep[lca(a,b)]*2;
    };
    rep(qq,q){
        vi v(3);rep(i,3)cin>>v[i];rep(i,3)v[i]--;
        vi al;
        rep(i,3)rep(j,i){
            ll d=dis(v[i],v[j]),l=lca(v[i],v[j]);
            ll cur=v[i];
            for(int k=19;k>=0;k--)if(table[cur][k]!=-1){
                if((dep[v[i]]-dep[table[cur][k]])*2<=d&&dep[l]<dep[table[cur][k]])cur=table[cur][k];
            }
            al.pb(cur);al.pb(par[cur]);
            cur=v[j];
            for(int k=19;k>=0;k--)if(table[cur][k]!=-1){
                if((dep[v[j]]-dep[table[cur][k]])*2<=d&&dep[l]<dep[table[cur][k]])cur=table[cur][k];
            }
            al.pb(cur);al.pb(par[cur]);
        }
        ll ans=inf;
        for(ll x:al)if(x!=-1)chmin(ans,max({dis(v[0],x),dis(v[1],x),dis(v[2],x)}));
        out(ans);
    }
}
accuracy: 1
time_ms: 840
memory_kb: 42844
final_rank: 17

code_snippet: #include <bits/stdc++.h>

using namespace std;

template<typename Graph>
struct Doubling {
public:
    int n, lg;
    const Graph g;

    vector<int> depth;
    vector<vector<int> > table, dist_table;
    vector<int> dist;

    Doubling(Graph &G) : g(G), n(G.size()), depth(G.size()), dist(G.size()) {
        lg = 32 - __builtin_clz(n) + 1;
        table.resize(n, vector(lg, 0));
        dist_table.resize(n, vector(lg, 0));
        dfs(0, -1, 0, 0);
        build();
    }

    int lca(int u, int v) {
        if (depth[u] < depth[v]) swap(u, v);
        for (int k = lg - 1; k >= 0; --k) {
            if (depth[u] - depth[v] >> k & 1) u = table[u][k];
        }
        if (u == v) return (u);
        for (int k = lg - 1; k >= 0; --k) {
            if (table[u][k] != table[v][k]) {
                u = table[u][k];
                v = table[v][k];
            }
        }
        return (table[u][0]);
    }

    /* u < v */
    int binary_search(int u, int v, int all) {
        int sum = 0;
        for (int k = lg - 1; k >= 0; --k) {
            if (depth[v] - depth[u] >= 1 << k && (sum + dist_table[v][k]) * 2 < all) {
                sum += dist_table[v][k];
                v = table[v][k];
            }
        }
        return (v);
    }

    int la(int u, int x) {
        for (int k = lg - 1; k >= 0; --k) {
            if (x >> k & 1) {
                u = table[u][k];
                x >>= 1;
            }
        }
        return (u);
    }

    int distance(int u, int v) {
        return (dist[u] + dist[v] - dist[lca(u, v)] * 2);
    }

private:

    void build() {
        for (int k = 0; k < lg - 1; ++k) {
            for (int i = 0; i < n; ++i) {
                if (table[i][k] != -1) {
                    table[i][k + 1] = table[table[i][k]][k];
                    dist_table[i][k + 1] = dist_table[i][k] + dist_table[table[i][k]][k];
                }
            }
        }
    }

    void dfs(int cur, int par, int dep, int dis) {
        depth[cur] = dep;
        table[cur][0] = par;
        dist[cur] = dis;
        for (auto [to, w] : g[cur]) {
            if (par == to) continue;
            dist_table[to][0] = w;
            dfs(to, cur, dep + 1, dis + w);
        }
    }
};

int main() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    int n, q;
    cin >> n >> q;

    vector<vector<pair<int, int> > > graph(n);

    for (int i = 0; i < n - 1; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        --u, --v;
        graph[u].emplace_back(v, w);
        graph[v].emplace_back(u, w);
    }

    Doubling dbl(graph);

    for (int i = 0; i < q; ++i) {
        int a, b, c;
        cin >> a >> b >> c;
        --a, --b, --c;

        int dist_ab = dbl.distance(a, b);
        int dist_ac = dbl.distance(a, c);
        int dist_bc = dbl.distance(b, c);
        int max_dist = max({dist_ab, dist_ac, dist_bc});

        int u, v;
        if (dist_ab == max_dist) u = a, v = b;
        if (dist_ac == max_dist) u = a, v = c;
        if (dist_bc == max_dist) u = b, v = c;

        int lca = dbl.lca(u, v), dist = max_dist;
        if (dbl.depth[u] > dbl.depth[v]) swap(u, v);

        if (lca != u) {
            if (dbl.distance(u, lca) > dbl.distance(lca, v)) swap(u, v);
            u = lca;
        }

        // cout << u << ' ' << v << ' ' << dist << '\n';
        int x = dbl.binary_search(u, v, dist);
        int y = max(dbl.la(x, 1), 0);
        // cout << x << ' ' << y << '\n';

        cout << min(max({dbl.distance(a, x), dbl.distance(b, x), dbl.distance(c, x)}),
                    max({dbl.distance(a, y), dbl.distance(b, y), dbl.distance(c, y)})) << '\n';
    }

    return (0);
}
accuracy: 1
time_ms: 290
memory_kb: 42680
final_rank: 11

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <iomanip>
#include <queue>
#include <string>
#include <map>
#include <fstream>
#include <cassert>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>


class Tree {
	std::vector<std::vector<int>> doubling;
	std::vector<int> depth, distance;
	int ancestor_from(int a, int diff) const {
		for (auto i = 0; diff != 0; ++i) {
			if (((diff >> i) & 1) == 1) {
				a = doubling[a][i];
				diff -= 1 << i;
			}
		}
		return a;
	}
	int lca(int a, int b) const {
		if (depth[a] != depth[b]) {
			if (depth[a] < depth[b]) std::swap(a, b);
			a = ancestor_from(a, depth[a] - depth[b]);
		}
		if (a == b) return a;
		if (doubling[a][0] == doubling[b][0]) return doubling[a][0];
		for (auto i = 1; i < doubling[a].size(); ++i) {
			if (doubling[a][i] == doubling[b][i]) return lca(doubling[a][i - 1], doubling[b][i - 1]);
		}
		return lca(doubling[a].back(), doubling[b].back());
	}
public:
	Tree(const std::vector<std::vector<std::pair<int, int>>>& node) : doubling(node.size()), depth(node.size()), distance(node.size()) {
		std::stack<std::pair<int, int>> stack;
		depth[0] = 0;
		distance[0] = 0;
		for (const auto [c, dist] : node[0]) {
			stack.emplace(0, c);
			depth[c] = depth[0] + 1;
			distance[c] = distance[0] + dist;
		}
		while (!stack.empty()) {
			const auto [parent, current] = stack.top(); stack.pop();
			doubling[current].push_back(parent);
			while (doubling[doubling[current].back()].size() >= doubling[current].size()) {
				doubling[current].push_back(doubling[doubling[current].back()][doubling[current].size() - 1]);
			}
			for (const auto [c, dist] : node[current]) {
				if (c == parent) continue;
				stack.emplace(current, c);
				depth[c] = depth[current] + 1;
				distance[c] = distance[current] + dist;
			}
		}
	}
	int distance_between(const int a, const int b) const {
		return distance[a] + distance[b] - (distance[lca(a, b)] << 1);
	}
	int count_between(const int a, const int b) const {
		return depth[a] + depth[b] - (depth[lca(a, b)] << 1) + 1;
	}
	int node(const int from, const int to, const int rank) const {
		const auto ancestor = lca(from, to);
		const auto left = depth[from] - depth[ancestor] + 1;
		const auto right = depth[to] - depth[ancestor];
		if (rank < left) return ancestor_from(from, rank);
		else return ancestor_from(to, left + right - 1 - rank);
	}
	int mid_node(const int a, const int b, const int c) const {
		const auto ab = lca(a, b);
		const auto bc = lca(b, c);
		const auto ca = lca(c, a);
		const auto max_depth = std::max({ depth[ab], depth[bc], depth[ca] });
		if (depth[ab] == max_depth) {
			return ab;
		}
		else if (depth[bc] == max_depth) {
			return bc;
		}
		else {
			return ca;
		}
	}
};

int main() {
	int n, q; std::cin >> n >> q;
	std::vector<std::vector<std::pair<int, int>>> nodes(n);
	for (auto i = 0; i < n - 1; ++i) {
		int u, v, w; std::cin >> u >> v >> w; --u; --v;
		nodes[u].emplace_back(v, w);
		nodes[v].emplace_back(u, w);
	}
	Tree tree(nodes);
	for (auto i = 0; i < q; ++i) {
		int a, b, c; std::cin >> a >> b >> c; --a; --b; --c;
		const auto center = tree.mid_node(a, b, c);
		if (tree.distance_between(center, a) < tree.distance_between(center, b)) {
			std::swap(a, b);
		}
		if (tree.distance_between(center, a) < tree.distance_between(center, c)) {
			std::swap(a, c);
		}
		if (tree.distance_between(center, b) < tree.distance_between(center, c)) {
			std::swap(b, c);
		}
		auto min = 0;
		auto max = tree.count_between(a, b);
		const auto dist = tree.distance_between(a, b);
		while (min < max) {
			const auto mid = (min + max) >> 1;
			const auto node = tree.node(a, b, mid);
			if (tree.distance_between(a, node) << 1 < dist) {
				min = mid + 1;
			}
			else {
				max = mid;
			}
		}
		const auto suspect = tree.node(a, b, max);
		auto min_cost{ std::max({tree.distance_between(a, suspect), tree.distance_between(b, suspect), tree.distance_between(c, suspect)}) };
		if (max > 0) {
			const auto suspect = tree.node(a, b, max - 1);
			min_cost = std::min(min_cost, std::max({ tree.distance_between(a, suspect), tree.distance_between(b, suspect), tree.distance_between(c, suspect) }));
		}
		std::cout << min_cost << '\n';
	}
}
accuracy: 1
time_ms: 740
memory_kb: 21764
final_rank: 5

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0391

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

#define call_from_test
#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
struct LevelAncestor{
  vector<vector<int> > G,par,lad;
  vector<int> dep,nxt,len,pth,ord,hs;
  LevelAncestor(int n):
    G(n),dep(n),nxt(n,-1),len(n),pth(n),ord(n),hs(n+1,0){
    int h=1;
    while((1<<h)<=n) h++;
    par.assign(h,vector<int>(n,-1));
    for(int i=2;i<=n;i++) hs[i]=hs[i>>1]+1;
  }

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void dfs(int v,int p,int d,int f){
    if(nxt[v]<0){
      par[0][nxt[v]=v]=p;
      len[v]=dep[v]=d;
      for(int u:G[v]){
        if(u==p) continue;
        dfs(u,v,d+1,0);
        if(len[v]<len[u]) nxt[v]=u,len[v]=len[u];
      }
    }
    if(!f) return;
    pth[v]=lad.size();
    lad.emplace_back();
    for(int k=v;;k=nxt[k]){
      lad.back().emplace_back(k);
      pth[k]=pth[v];
      if(k==nxt[k]) break;
    }
    for(;;p=v,v=nxt[v]){
      for(int u:G[v])
        if(u!=p and u!=nxt[v]) dfs(u,v,d+1,1);
      if(v==nxt[v]) break;
    }
  }

  void build(int r=0){
    int n=G.size();
    dfs(r,-1,0,1);
    for(int k=0;k+1<(int)par.size();k++){
      for(int v=0;v<n;v++){
        if(par[k][v]<0) par[k+1][v]=-1;
        else par[k+1][v]=par[k][par[k][v]];
      }
    }
    for(int i=0;i<(int)lad.size();i++){
      int v=lad[i][0],p=par[0][v];
      if(~p){
        int k=pth[p],l=min(ord[p]+1,(int)lad[i].size());
        lad[i].resize(l+lad[i].size());
        for(int j=0,m=lad[i].size();j+l<m;j++)
          lad[i][m-(j+1)]=lad[i][m-(j+l+1)];
        for(int j=0;j<l;j++)
          lad[i][j]=lad[k][ord[p]-l+j+1];
      }
      for(int j=0;j<(int)lad[i].size();j++)
        if(pth[lad[i][j]]==i) ord[lad[i][j]]=j;
    }
  }

  int lca(int u,int v){
    int h=par.size();

    if(dep[u]>dep[v]) swap(u,v);
    for(int k=0;k<h;k++)
      if((dep[v]-dep[u])>>k&1)
        v=par[k][v];

    if(u==v) return u;
    for(int k=h-1;k>=0;k--){
      if(par[k][u]==par[k][v]) continue;
      u=par[k][u];
      v=par[k][v];
    }
    return par[0][u];
  }

  int distance(int u,int v){
    return dep[u]+dep[v]-dep[lca(u,v)]*2;
  }

  int up(int v,int d){
    if(d==0) return v;
    v=par[hs[d]][v];
    d-=1<<hs[d];
    return lad[pth[v]][ord[v]-d];
  }

  // from u to v
  int next(int u,int v){
    if(dep[u]>=dep[v]) return par[0][u];
    int l=up(v,dep[v]-dep[u]-1);
    return par[0][l]==u?l:par[0][u];
  }
};
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n,q;
  cin>>n>>q;
  using P = pair<int, int>;
  vector<vector<P> > G(n);
  LevelAncestor la(n);
  for(int i=1;i<n;i++){
    int u,v,w;
    cin>>u>>v>>w;
    u--;v--;
    la.add_edge(u,v);
    G[u].emplace_back(v,w);
    G[v].emplace_back(u,w);
  }

  la.build();

  vector<int> dep(n,0);
  {
    queue<P> q;
    q.emplace(0,-1);
    while(!q.empty()){
      int v,p;
      tie(v,p)=q.front();q.pop();
      for(auto e:G[v]){
        int u,c;
        tie(u,c)=e;
        if(u==p) continue;
        dep[u]=dep[v]+c;
        q.emplace(u,v);
      }
    }
  }

  auto dist=[&](int u,int v){return dep[u]+dep[v]-2*dep[la.lca(u,v)];};
  auto path=
    [&](int u,int v,int d){
      if(d==0) return u;
      int r=la.lca(u,v);
      int x=la.distance(u,r),y=la.distance(r,v);
      if(d<=x) return la.up(u,d);
      return la.up(v,(x+y)-d);
    };

  for(int i=0;i<q;i++){
    int a,b,c;
    cin>>a>>b>>c;
    a--;b--;c--;
    auto calc=
      [&](int v,int u=-1){
        return max({dist(a,v)*(a!=u),
                    dist(b,v)*(b!=u),
                    dist(c,v)*(c!=u)});
      };

    int p=la.lca(a,b),q=la.lca(b,c),r=la.lca(c,a);
    int v=la.dep[p]>la.dep[q]?p:(la.dep[q]>la.dep[r]?q:r);

    int ans=min({calc(a),calc(b),calc(c),calc(v)});
    for(int u:{a,b,c}){
      if(calc(v,u)>=ans) continue;
      int l=0,r=la.distance(u,v);
      while(l+1<r){
        int m=(l+r)>>1;
        int x=path(u,v,m);
        if(calc(x,u)<dist(x,u)) r=m;
        else l=m;
      }
      chmin(ans,calc(path(u,v,l)));
      chmin(ans,calc(path(u,v,r)));
    }
    cout<<ans<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 1310
memory_kb: 34788
final_rank: 18

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

class HeavyLightDecomposition {
    void dfs_sz(int v){
        for (auto &&u : G[v]) {
            if(u == par[v]) continue;
            par[u] = v; dep[u] = dep[v] + 1;
            dfs_sz(u);
            sub_size[v] += sub_size[u];
            if(sub_size[u] > sub_size[G[v][0]]) swap(u, G[v][0]);
        }
    }

    void dfs_hld(int v, int c, int &pos){
        id[v] = pos++;
        id_inv[id[v]]= v;
        tree_id[v] = c;
        for (auto &&u : G[v]) {
            if(u == par[v]) continue;
            head[u] = (u == G[v][0] ? head[v] : u);
            dfs_hld(u, c, pos);
        }
    }

public:
    int n;
    vector<vector<int>> G;
    vector<int> par, dep, sub_size, id, id_inv, tree_id, head;
    explicit HeavyLightDecomposition(int n) : n(n), G(n), par(n), dep(n), sub_size(n, 1),
    id(n), id_inv(n), tree_id(n), head(n){}
    explicit HeavyLightDecomposition(vector<vector<int>> &G) :
    G(G), n(G.size()), par(n), dep(n) , sub_size(n, 1), id(n), id_inv(n), tree_id(n), head(n) {}

    void add_edge(int u, int v){
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }

    void build(vector<int> roots = {0}){
        int c = 0, pos = 0;
        for (auto &&i : roots) {
            dfs_sz(i);
            head[i] = i;
            dfs_hld(i, c++, pos);
        }
    }

    int ancestor(int v, int k){
        while(true){
            int u = head[v];
            if(id[v] - k >= id[u]) return id_inv[id[v]-k];
            k -= id[v] - id[u] + 1;
            v = par[u];
        }
    }

    int lca(int u, int v){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            if(head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }

    int distance(int u, int v){
        return dep[u] + dep[v] - 2*dep[lca(u, v)];
    }


    template<typename F>
    void query(int u, int v, const F &f){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            f(max(id[head[v]], id[u]), id[v]+1);
            if(head[u] == head[v]) break;
            v = par[head[v]];
        }
    }

    template<typename F>
    void query_edge(int u, int v, const F &f){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            f(max(id[head[v]], id[u]), id[v]+1);
            if(head[u] == head[v]) {
                if(u == v) break;
                f(id[u], id[v]+1);
            }else {
                v = par[head[v]];
            }
        }
    }

    template<typename T, typename Q, typename F>
    T query(int u, int v, const T &e, const Q &q, const F &f){
        T l = e, r = e;
        while(true){
            if(id[u] > id[v]) swap(u, v), swap(l, r);
            l = f(l, q(max(id[head[v]], id[u]), id[v]+1));
            if(head[u] != head[v]) v = par[head[v]];
            else break;
        }
        return f(l, r);
    }
};

template<class T> void chmin(T &a, const T &b){ a = (a < b ? a : b); }
template<class T> void chmax(T &a, const T &b){ a = (a > b ? a : b); }


int main() {
    int n, q;
    cin >> n >> q;
    HeavyLightDecomposition G(n);
    vector<vector<pair<int, int>>> g(n);
    for (int i = 0; i < n-1; ++i) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        u--; v--;
        G.add_edge(u, v);
        g[u].emplace_back(v, w);
        g[v].emplace_back(u, w);
    }
    G.build();
    vector<int> dep(n);
    auto dfs = [&](int x, int par, auto &&f) -> void {
        for (auto &&e : g[x]) {
            if(e.first != par) {
                dep[e.first] = dep[x] + e.second;
                f(e.first, x, f);
            }
        }
    };
    auto d = [&](int x, int y){ return dep[x] + dep[y] - 2*dep[G.lca(x, y)]; };
    dfs(0, -1, dfs);
    while(q--){
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        a--; b--; c--;
        int x = G.lca(a, G.lca(b, c));
        int ans = INF<int>;
        for (auto &&v : {a, b, c}) {
            int l = 0, r = G.distance(v, x);
            while(r-l > 1){
                int mid = (l+r)/2;
                int u = G.ancestor(v, mid);
                int val = 0;
                for (auto &&i : {a, b, c}) {
                    if(i != v) chmax(val, d(u, i));
                }
                if(d(v, u) < val) l = mid;
                else r = mid;
            }
            l = G.ancestor(v, l), r = G.ancestor(v, r);
            chmin(ans, max({d(l, a), d(l, b), d(l, c)}));
            chmin(ans, max({d(r, a), d(r, b), d(r, c)}));
        }
        cout << ans << "\n";
    }
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 24920
final_rank: 2

code_snippet: #include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int inf = 2012345678;
class edge {
public:
	int to, cost;
	explicit edge() : to(-1), cost(0) {};
	explicit edge(int to_, int cost_) : to(to_), cost(cost_) {};
};
vector<int> solve(int N, int Q, vector<int> A, vector<int> B, vector<int> C, vector<int> X, vector<int> Y, vector<int> Z) {
	vector<vector<edge> > G(N);
	for (int i = 0; i < N - 1; ++i) {
		G[A[i]].push_back(edge(B[i], C[i]));
		G[B[i]].push_back(edge(A[i], C[i]));
	}
	vector<int> par(N, -1), depth(N), wdepth(N), el(N), er(N);
	int current = 0;
	function<void(int, int)> build_tree = [&](int pos, int pre) {
		par[pos] = pre;
		el[pos] = current++;
		for (edge e : G[pos]) {
			if (e.to == pre) continue;
			depth[e.to] = depth[pos] + 1;
			wdepth[e.to] = wdepth[pos] + e.cost;
			build_tree(e.to, pos);
		}
		er[pos] = current;
	};
	build_tree(0, 0);
	int bits = 1;
	while ((1 << bits) < N) ++bits;
	vector<vector<int> > p(bits, vector<int>(N));
	p[0] = par;
	for (int i = 1; i < bits; ++i) {
		for (int j = 0; j < N; ++j) {
			p[i][j] = p[i - 1][p[i - 1][j]];
		}
	}
	function<int(int, int)> lca = [&](int x, int y) {
		if (depth[x] < depth[y]) swap(x, y);
		for (int i = bits - 1; i >= 0; --i) {
			if ((depth[x] - depth[y]) >= (1 << i)) {
				x = p[i][x];
			}
		}
		if (x == y) return x;
		for (int i = bits - 1; i >= 0; --i) {
			if (p[i][x] != p[i][y]) {
				x = p[i][x];
				y = p[i][y];
			}
		}
		return p[0][x];
	};
	function<int(int, int)> dist_lca = [&](int x, int y) {
		return wdepth[x] + wdepth[y] - wdepth[lca(x, y)] * 2;
	};
	function<bool(int, int)> is_ancestor = [&](int x, int y) {
		// check if x is an ancestor of y
		return el[x] <= el[y] && er[y] <= er[x];
	};
	vector<int> ans(Q, inf);
	for (int id = 0; id < Q; ++id) {
		int xy = lca(X[id], Y[id]);
		int yz = lca(Y[id], Z[id]);
		int zx = lca(Z[id], X[id]);
		vector<int> verts = { X[id], Y[id], Z[id], xy, yz, zx };
		sort(verts.begin(), verts.end());
		verts.erase(unique(verts.begin(), verts.end()), verts.end());
		int S = verts.size();
		vector<int> spar(S, -1);
		for (int i = 0; i < S; ++i) {
			int ptr = -1;
			for (int j = 0; j < S; ++j) {
				if (i != j && is_ancestor(verts[j], verts[i]) && (ptr == -1 || depth[ptr] < depth[j])) {
					ptr = j;
				}
			}
			spar[i] = ptr;
		}
		vector<int> farthest(S, -1); // 0 -> X, 1 -> Y, 2 -> Z
		vector<vector<int> > D(S, vector<int>(3));
		for (int i = 0; i < S; ++i) {
			D[i][0] = dist_lca(X[id], verts[i]);
			D[i][1] = dist_lca(Y[id], verts[i]);
			D[i][2] = dist_lca(Z[id], verts[i]);
			farthest[i] = max_element(D[i].begin(), D[i].end()) - D[i].begin();
			ans[id] = min(ans[id], D[i][farthest[i]]);
		}
		for (int i = 0; i < S; ++i) {
			if (spar[i] == -1 || farthest[i] == farthest[spar[i]]) continue;
			int pos = verts[i], tar = verts[spar[i]];
			int da = D[i][farthest[i]], db = D[i][farthest[spar[i]]];
			for (int j = bits - 1; j >= 0; --j) {
				if (depth[pos] - depth[tar] > (1 << j)) {
					int npos = p[j][pos];
					int nda = da - (wdepth[pos] - wdepth[npos]);
					int ndb = db + (wdepth[pos] - wdepth[npos]);
					if (nda > ndb) {
						pos = npos;
						da = nda;
						db = ndb;
					}
				}
			}
			ans[id] = min(ans[id], da);
			ans[id] = min(ans[id], db + (wdepth[pos] - wdepth[par[pos]]));
		}
	}
	return ans;
}
vector<int> solve_easy(int N, int Q, vector<int> A, vector<int> B, vector<int> C, vector<int> X, vector<int> Y, vector<int> Z) {
	vector<vector<edge> > G(N);
	for (int i = 0; i < N - 1; ++i) {
		G[A[i]].push_back(edge(B[i], C[i]));
		G[B[i]].push_back(edge(A[i], C[i]));
	}
	vector<vector<int> > dist(N, vector<int>(N));
	for (int i = 0; i < N; ++i) {
		function<void(int, int)> calc_dist = [&](int pos, int pre) {
			for (edge e : G[pos]) {
				if (e.to == pre) continue;
				dist[i][e.to] = dist[i][pos] + e.cost;
				calc_dist(e.to, pos);
			}
		};
		calc_dist(i, -1);
	}
	vector<int> ans(Q, inf);
	for (int i = 0; i < Q; ++i) {
		for (int j = 0; j < N; ++j) {
			ans[i] = min(ans[i], max({ dist[X[i]][j], dist[Y[i]][j], dist[Z[i]][j] }));
		}
	}
	return ans;
}
#include <random>
#include <string>
mt19937 mt(2009102116);
class disjoint_set {
private:
	int N;
	vector<int> par;
public:
	disjoint_set() : N(0), par() {};
	disjoint_set(int N_) : N(N_), par(N_) {
		for (int i = 0; i < N_; ++i) {
			par[i] = i;
		}
	}
	int root(int x) {
		if (x == par[x]) return x;
		return par[x] = root(par[x]);
	}
	void link(int x, int y) {
		par[root(x)] = root(y);
	}
	bool connected(int x, int y) {
		return root(x) == root(y);
	}
};
string to_string(vector<int> arr) {
	string res = "[";
	for (int i = 0; i < arr.size(); ++i) {
		if (i) res += ", ";
		res += to_string(arr[i]);
	}
	res += "]";
	return res;
}
int rand_rng(int l, int r) {
	uniform_int_distribution<int> p(l, r - 1);
	return p(mt);
}
void random_gen() {
	int repeat = 300000;
	for (int N = 3; N <= 10; ++N) {
		int Q = 1;
		for (int rep = 1; rep <= repeat; ++rep) {
			disjoint_set uf(N);
			vector<int> A(N - 1), B(N - 1), C(N - 1);
			for (int i = 0; i < N - 1; ++i) {
				do {
					A[i] = rand_rng(0, N);
					B[i] = rand_rng(0, N);
				} while (uf.connected(A[i], B[i]));
				uf.link(A[i], B[i]);
				C[i] = rand_rng(1, 10);
			}
			vector<int> X(Q), Y(Q), Z(Q);
			for (int i = 0; i < Q; ++i) {
				do {
					X[i] = rand_rng(0, N);
					Y[i] = rand_rng(0, N);
					Z[i] = rand_rng(0, N);
				} while (X[i] == Y[i] || Y[i] == Z[i] || Z[i] == X[i]);
			}
			vector<int> res1 = solve(N, Q, A, B, C, X, Y, Z);
			vector<int> res2 = solve_easy(N, Q, A, B, C, X, Y, Z);
			if (res1 != res2) {
				cout << "N = " << N << " / Case #" << rep << ":" << endl;
				cout << "A = " << to_string(A) << endl;
				cout << "B = " << to_string(B) << endl;
				cout << "C = " << to_string(C) << endl;
				cout << "X = " << to_string(X) << endl;
				cout << "Y = " << to_string(Y) << endl;
				cout << "Z = " << to_string(Z) << endl;
				cout << "Returns: " << to_string(res1) << endl;
				cout << "Answer: " << to_string(res2) << endl;
				cout << endl;
			}
		}
		cout << "N = " << N << " Completed!" << endl;
		cout << endl;
	}
}
int main() {
	// random_gen();
	cin.tie(0);
	ios_base::sync_with_stdio(false);
	int N, Q;
	cin >> N >> Q;
	vector<int> A(N - 1), B(N - 1), C(N - 1);
	for (int i = 0; i < N - 1; ++i) {
		cin >> A[i] >> B[i] >> C[i];
		--A[i], --B[i];
	}
	vector<int> X(Q), Y(Q), Z(Q);
	for (int i = 0; i < Q; ++i) {
		cin >> X[i] >> Y[i] >> Z[i];
		--X[i], --Y[i], --Z[i];
	}
	vector<int> res = solve(N, Q, A, B, C, X, Y, Z);
	for (int i = 0; i < Q; ++i) {
		cout << res[i] << '\n';
	}
	return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 31304
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
using UL = unsigned int;
using ULL = unsigned long long;
using LL = long long;
#define rep(i, n) for(UL i = 0; i < (n); i++)

UL N, Q;
UL P[100000][18];
UL D[100000];
UL C[100000];
vector<pair<UL, UL>> E[100000];

UL LCA(UL a, UL b) {
	if (C[a] < C[b]) swap(a, b);
	UL d = C[a] - C[b];
	for (UL i = 17; i != ~0u; i--) {
		if ((1u << i) & d) a = P[a][i];
	}
	if (a == b) return a;
	for (UL i = 17; i != ~0u; i--) {
		if (P[a][i] == P[b][i]) continue;
		a = P[a][i]; b = P[b][i];
	}
	return P[a][0];
}

pair<UL, UL> MP(UL a, UL b) {
	UL X = D[LCA(a, b)];
	if (D[a] < D[b]) swap(a, b);
	UL Y = D[a] - D[b] + X + X;
	for (UL i = 17; i != ~0u; i--) {
		if (D[P[a][i]] * 2 <= Y) continue;
		a = P[a][i];
	}
	if (X == D[a]) return{ a,a };
	else return { a, P[a][0] };
}

UL Dist(UL a, UL b) {
	UL X = D[LCA(a, b)];
	return D[a] + D[b] - X - X;
}

int main() {
	scanf("%u%u", &N, &Q);
	rep(i, N - 1) {
		UL u, v, w; scanf("%u%u%u", &u, &v, &w); u--; v--;
		E[u].push_back({ v, w });
		E[v].push_back({ u, w });
	}
	{
		P[0][0] = 0; D[0] = 0; C[0] = 0;
		queue<UL> G; G.push(0);
		while (G.size()) {
			UL p = G.front(); G.pop();
			for (auto& e : E[p]) {
				if (P[p][0] == e.first) continue;
				P[e.first][0] = p;
				D[e.first] = D[p] + e.second;
				C[e.first] = C[p] + 1;
				G.push(e.first);
			}
		}
	}
	rep(i, 17) rep(j, N) P[j][i + 1] = P[P[j][i]][i];

	rep(q, Q) {
		UL a, b, c; scanf("%u%u%u", &a, &b, &c); a--; b--; c--;
		UL ans = ~0u;
		rep(t, 3) {
			auto mp = MP(a, b);
			UL q1 = max(max(Dist(mp.first, a), Dist(mp.first, b)), Dist(mp.first, c));
			UL q2 = max(max(Dist(mp.second, a), Dist(mp.second, b)), Dist(mp.second, c));
			ans = min(ans, min(q1, q2));
			swap(a, b); swap(b, c);
		}
		printf("%u\n", ans);
	}
	return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 17116
final_rank: 1

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


struct edge{ int to,cost; };
int N,Q;

vector<edge> G[100005];

int parent[100005];
int depth[100005];
int dist[100005];

int p[30][100005];
void dfs(int pos,int prev,int Depth,int Dist){
  parent[pos]=prev;
  depth[pos]=Depth;
  dist[pos]=Dist;
  for(int i=0;i<(int)G[pos].size();i++){
    edge e=G[pos][i];
    if(e.to==prev)continue;
    dfs(e.to,pos,Depth+1,Dist+e.cost);
  }
}

int lca(int a,int b){
  if(depth[a]>depth[b])swap(a,b);
  
  int s=(depth[b]-depth[a]);
  for(int i=0;i<30;i++)
    if(s>>i&1)
      b=p[i][b];
  
  if(a==b)return a;
  
  for(int i=29;i>=0;i--){
    if( p[i][a] != p[i][b] ){
      a=p[i][a];
      b=p[i][b];
    }
  }
  return parent[a];
}

int calc_dist(int a,int b){
  int c=lca(a,b);
  return dist[a]-dist[c]+dist[b]-dist[c];
}

int check(int p,int a,int b,int c){
  int res=0;
  res=max(res, calc_dist(p,a));
  res=max(res, calc_dist(p,b));
  res=max(res, calc_dist(p,c));
  return res;
}

int solve(int a,int b,int c){
  int x=lca(b,c);
  if( calc_dist(x,b) > calc_dist(x,c) )swap(b,c);
  
  int y=calc_dist(b,c)/2;
  int z=c;
  for(int i=29;i>=0;i--){
    int nz=p[i][z];
    if(nz!=-1 && (dist[c]-dist[nz]) <= y){
      z=nz;
    }
  }
  
  int res=check(z,a,b,c);
  if( parent[z]!=-1 )
    res=min(res,check(parent[z],a,b,c));
  return res;
}

int main(){
  scanf("%d %d",&N,&Q);
  for(int i=0;i<N-1;i++){
    int u,v,w;
    scanf("%d %d %d",&u,&v,&w);
    u--;
    v--;
    G[u].push_back( (edge){v,w} );
    G[v].push_back( (edge){u,w} );
    
  }
  
  dfs(0,-1,0,0);

  for(int i=0;i<N;i++)
    p[0][i]=parent[i];

  for(int i=1;i<30;i++){
    for(int j=0;j<N;j++){
      int x=p[i-1][j];
      if(x!=-1)x=p[i-1][x];
      p[i][j]=x;
    }
  }

  for(int i=0;i<Q;i++){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    a--;
    b--;
    c--;
    int ans=(1<<30);
    ans=min(ans, solve(a,b,c) );
    ans=min(ans, solve(b,a,c) );
    ans=min(ans, solve(c,a,b) );
    printf("%d\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 520
memory_kb: 27844
final_rank: 4

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


struct edge{ int to,cost; };
int N,Q;

vector<edge> G[100005];

int parent[100005];
int depth[100005];
int dist[100005];

int p[30][100005];
void dfs(int pos,int prev,int Depth,int Dist){
  parent[pos]=prev;
  depth[pos]=Depth;
  dist[pos]=Dist;
  for(int i=0;i<(int)G[pos].size();i++){
    edge e=G[pos][i];
    if(e.to==prev)continue;
    dfs(e.to,pos,Depth+1,Dist+e.cost);
  }
}

int lca(int a,int b){
  if(depth[a]>depth[b])swap(a,b);
  
  int s=(depth[b]-depth[a]);
  for(int i=0;i<30;i++)
    if(s>>i&1)
      b=p[i][b];
  
  if(a==b)return a;
  
  for(int i=29;i>=0;i--){
    if( p[i][a] != p[i][b] ){
      a=p[i][a];
      b=p[i][b];
    }
  }
  return parent[a];
}

int calc_dist(int a,int b){
  int c=lca(a,b);
  return dist[a]-dist[c]+dist[b]-dist[c];
}

int check(int p,int a,int b,int c){
  int res=0;
  res=max(res, calc_dist(p,a));
  res=max(res, calc_dist(p,b));
  res=max(res, calc_dist(p,c));
  return res;
}

int solve(int a,int b,int c){
  int x=lca(b,c);
  if( calc_dist(x,b) > calc_dist(x,c) )swap(b,c);
  
  int y=calc_dist(b,c)/2;
  int z=c;
  for(int i=29;i>=0;i--){
    int nz=p[i][z];
    if(nz!=-1 && calc_dist(c,nz) <= y){
      z=nz;
    }
  }
  
  int res=check(z,a,b,c);
  if( parent[z]!=-1 )
    res=min(res,check(parent[z],a,b,c));
  return res;
}

int main(){
  scanf("%d %d",&N,&Q);
  for(int i=0;i<N-1;i++){
    int u,v,w;
    scanf("%d %d %d",&u,&v,&w);
    u--;
    v--;
    G[u].push_back( (edge){v,w} );
    G[v].push_back( (edge){u,w} );
    
  }
  
  dfs(0,-1,0,0);

  for(int i=0;i<N;i++)
    p[0][i]=parent[i];

  for(int i=1;i<30;i++){
    for(int j=0;j<N;j++){
      int x=p[i-1][j];
      if(x!=-1)x=p[i-1][x];
      p[i][j]=x;
    }
  }

  for(int i=0;i<Q;i++){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    a--;
    b--;
    c--;
    int ans=(1<<30);
    ans=min(ans, solve(a,b,c) );
    ans=min(ans, solve(b,a,c) );
    ans=min(ans, solve(c,a,b) );
    printf("%d\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 710
memory_kb: 27876
final_rank: 9

code_snippet: #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0391"

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

#define call_from_test
#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
using Int = long long;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
using Int = long long;
#endif
//BEGIN CUT HERE
struct LCA{
  const int lg = 12;
  const int sz = 1<<lg;
  const int ms = sz-1;
  int n;
  vector<int> P,D,E,A,B,T,ht;
  vector<vector<int> > G,dat;
  LCA(int n):
    n(n),P(n,-1),D(n),E(n*2,0),A(n*2,-1),B(n*2/lg+1),T(sz,0),G(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void dfs(int v,int p,int d){
    int k=0,u;
    vector<int> iter(n,0);

    using T = tuple<int, int, int>;
    stack<T> st;

  START:
    D[v]=k;
    A[k]=P[v]=p;
    E[k++]=d;
    for(;iter[v]<(int)G[v].size();iter[v]++){
      u=G[v][iter[v]];
      if(u==p) continue;
      st.emplace(v,p,d);
      p=v;v=u;d=d+1;
      goto START;
    END:
      tie(v,p,d)=st.top();st.pop();
    }

    A[k]=P[v];
    E[k++]=d-1;

    if(!st.empty()) goto END;
  }

  // if it need leftmost, then add: if(E[i]==E[j]) return i<j?i:j;
  inline int comp(int i,int j){return E[i]<E[j]?i:j;};
  inline int comp(int i,int j,int k){return comp(comp(i,j),k);};

  void build(int r=0){
    dfs(r,-1,1);

    B[0]=1;
    for(int i=1;i<n*2;i++) B[i/lg]|=(E[i-1]<E[i])<<(i%lg);

    for(int b=0;b<sz;b++){
      int e=0,w=1,&x=T[b];
      for(int i=0;i<lg;i++){
        if((b>>i)&1) e++;
        else e--;
        if(e<w) e=w,x=i;
      }
    }

    int m=(n*2+lg-1)/lg;
    int h=1;
    while((1<<h)<m) h++;
    dat.assign(h,vector<int>(m,-1));
    ht.assign(m+1,0);
    for(int j=2;j<=m;j++) ht[j]=ht[j>>1]+1;

    for(int j=0;j<n*2;j++){
      if(dat[0][j/lg]<0) dat[0][j/lg]=j;
      dat[0][j/lg]=comp(dat[0][j/lg],j);
    }

    for(int i=1,p=1;i<h;i++,p<<=1)
      for(int j=0;j<m;j++)
        dat[i][j]=comp(dat[i-1][j],dat[i-1][min(j+p,m-1)]);
  }

  inline int cs(int a,int b){
    int l=b-a;
    return comp(dat[ht[l]][a],dat[ht[l]][b-(1<<ht[l])]);
  }

  inline int es(int i,int l,int r){
    int x=r-i*lg+1,y=l-i*lg;
    int b=(((B[i]|(ms<<x))>>y)|(ms<<(lg-y)))&ms;
    return l+T[b];
  }

  inline int ls(int i,int l){
    int k=l-i*lg;
    int b=((B[i]>>k)|(ms<<(lg-k)))&ms;
    return l+T[b];
  }

  inline int rs(int j,int r){
    int k=r-j*lg+1;
    int b=(B[j]|(ms<<k))&ms;
    return j*lg+T[b];
  }

  inline int rmq(int l,int r){
    int i=l/lg,j=r/lg;
    if(i==j) return es(i,l,r);
    if(i+1==j) return comp(ls(i,l),rs(j,r));
    return comp(ls(i,l),cs(i+1,j),rs(j,r));
  }

  int lca(int l,int r){
    if(l==r) return l;
    if(D[l]>D[r]) swap(l,r);
    int x=D[l],y=D[r];
    int m=rmq(x,y);
    return m==x?l:A[m];
  }
};
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
struct LevelAncestor{
  int n,h;
  vector<vector<int> > G,par,lad;
  vector<int> dep,nxt,len,pth,ord,hs;
  LevelAncestor(){}
  LevelAncestor(int n):
    n(n),G(n),dep(n),nxt(n,-1),len(n),pth(n),ord(n),hs(n+1,0){
    h=1;
    while((1<<h)<=n) h++;
    par.assign(h,vector<int>(n,-1));
    for(int i=2;i<=n;i++) hs[i]=hs[i>>1]+1;
  }

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void dfs(int v,int p,int d,int f){
    if(nxt[v]<0){
      par[0][nxt[v]=v]=p;
      len[v]=dep[v]=d;
      for(int u:G[v]){
        if(u==p) continue;
        dfs(u,v,d+1,0);
        if(len[v]<len[u]) nxt[v]=u,len[v]=len[u];
      }
    }
    if(!f) return;
    pth[v]=lad.size();
    lad.emplace_back();
    for(int k=v;;k=nxt[k]){
      lad.back().emplace_back(k);
      pth[k]=pth[v];
      if(k==nxt[k]) break;
    }
    for(;;p=v,v=nxt[v]){
      for(int u:G[v])
        if(u!=p&&u!=nxt[v]) dfs(u,v,d+1,1);
      if(v==nxt[v]) break;
    }
  }

  void build(int r=0){
    dfs(r,-1,0,1);
    for(int k=0;k+1<h;k++){
      for(int v=0;v<n;v++){
        if(par[k][v]<0) par[k+1][v]=-1;
        else par[k+1][v]=par[k][par[k][v]];
      }
    }
    for(int i=0;i<(int)lad.size();i++){
      int v=lad[i][0],p=par[0][v];
      if(~p){
        int k=pth[p],l=min(ord[p]+1,(int)lad[i].size());
        lad[i].resize(l+lad[i].size());
        for(int j=0,m=lad[i].size();j+l<m;j++)
          lad[i][m-(j+1)]=lad[i][m-(j+l+1)];
        for(int j=0;j<l;j++)
          lad[i][j]=lad[k][ord[p]-l+j+1];
      }
      for(int j=0;j<(int)lad[i].size();j++)
        if(pth[lad[i][j]]==i) ord[lad[i][j]]=j;
    }
  }

  int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    for(int k=0;k<h;k++){
      if((dep[v]-dep[u])>>k&1){
        v=par[k][v];
      }
    }
    if(u==v) return u;
    for(int k=h-1;k>=0;k--){
      if(par[k][u]!=par[k][v]){
        u=par[k][u];
        v=par[k][v];
      }
    }
    return par[0][u];
  }

  int up(int v,int d){
    if(d==0) return v;
    v=par[hs[d]][v];
    d-=1LL<<hs[d];
    return lad[pth[v]][ord[v]-d];
  }

  int distance(int u,int v){
    return dep[u]+dep[v]-dep[lca(u,v)]*2;
  }
};
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
char buf[256];
signed solve(){
  using ll = long long;
  int n;
  scanf("%d",&n);
  using P = pair<int, int>;
  vector<vector<P> > G(n);
  LevelAncestor la(n);
  for(int i=1;i<n;i++){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    a--;b--;
    la.add_edge(a,b);
    G[a].emplace_back(b,c);
    G[b].emplace_back(a,c);
  }
  la.build();

  vector<ll> dep(n,0);
  {
    queue<P> q;
    q.emplace(0,-1);
    while(!q.empty()){
      int v,p;
      tie(v,p)=q.front();q.pop();
      for(auto e:G[v]){
        int u,c;
        tie(u,c)=e;
        if(u==p) continue;
        dep[u]=dep[v]+c;
        q.emplace(u,v);
      }
    }
  }

  while(scanf("%s",buf)){
    string s(buf);
    if(s=="DONE"s) break;
    if(s=="DIST"s){
      int a,b;
      scanf("%d %d",&a,&b);
      a--;b--;
      printf("%lld\n",dep[a]+dep[b]-2*dep[la.lca(a,b)]);
    }
    if(s=="KTH"s){
      int a,b,k;
      scanf("%d %d %d",&a,&b,&k);
      a--;b--;k--;
      int l=la.lca(a,b);
      int x=la.distance(a,l),y=la.distance(l,b);
      assert(0<=k&&k<=x+y);
      printf("%d\n",(k<=x?la.up(a,k):la.up(b,x+y-k))+1);
    }
  }
  return 0;
}

signed SPOJ_QTREE2(){
  int t;
  scanf("%d",&t);
  for(int i=0;i<t;i++) solve();
  return 0;
}
/*
  verified on 2019/10/25
  https://www.spoj.com/problems/QTREE2/
*/

signed main(){
  SPOJ_QTREE2();
  return 0;
}
#endif

#undef call_from_test

signed main(){
  int n,q;
  scanf("%d %d",&n,&q);
  using P = pair<int, int>;
  vector<vector<P> > G(n);
  LCA lca(n);
  LevelAncestor la(n);
  for(int i=1;i<n;i++){
    int u,v,w;
    scanf("%d %d %d",&u,&v,&w);
    u--;v--;
    lca.add_edge(u,v);
    la.add_edge(u,v);
    G[u].emplace_back(v,w);
    G[v].emplace_back(u,w);
  }

  lca.build();
  la.build();

  vector<int> dep(n,0);
  {
    queue<P> q;
    q.emplace(0,-1);
    while(!q.empty()){
      int v,p;
      tie(v,p)=q.front();q.pop();
      for(auto e:G[v]){
        int u,c;
        tie(u,c)=e;
        if(u==p) continue;
        dep[u]=dep[v]+c;
        q.emplace(u,v);
      }
    }
  }

  auto dist=[&](int u,int v){return dep[u]+dep[v]-2*dep[lca.lca(u,v)];};
  auto path=
    [&](int u,int v,int d){
      if(d==0) return u;
      int r=lca.lca(u,v);
      int x=la.distance(u,r),y=la.distance(r,v);
      if(d<=x) return la.up(u,d);
      return la.up(v,(x+y)-d);
    };

  for(int i=0;i<q;i++){
    int a,b,c;
    scanf("%d %d %d",&a,&b,&c);
    a--;b--;c--;
    auto calc=
      [&](int v,int u=-1){
        return max({dist(a,v)*(a!=u),
                    dist(b,v)*(b!=u),
                    dist(c,v)*(c!=u)});
      };

    int p=lca.lca(a,b),q=lca.lca(b,c),r=lca.lca(c,a);
    int v=la.dep[p]>la.dep[q]?p:(la.dep[q]>la.dep[r]?q:r);

    int ans=min({calc(a),calc(b),calc(c),calc(v)});
    for(int u:{a,b,c}){
      if(calc(v,u)>=ans) continue;
      int l=0,r=la.distance(u,v);
      while(l+1<r){
        int m=(l+r)>>1;
        int x=path(u,v,m);
        if(calc(x,u)<dist(x,u)) r=m;
        else l=m;
      }
      chmin(ans,calc(path(u,v,l)));
      chmin(ans,calc(path(u,v,r)));
    }
    printf("%d\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 37212
final_rank: 10