/*  Author: Gurdeep Singh
 *  Codeforces: gdb_18 
 *  Codechef: gurdeep1810 
**/

// #pragma comment(linker, "/stack:200000000")
// #pragma GCC optimize("Ofast")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

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

using namespace std;
using namespace __gnu_pbds;
using i128 = __int128_t;
using u128 = __uint128_t;           // Do not use I/O for this
using i64 = int64_t;
using u64 = uint64_t;

typedef long long int ll;
typedef unsigned long long int ull;
typedef long double ld;

#define mp make_pair
#define ff first
#define ss second
#define bipc __builtin_popcountll   // count number of set bits
#define lb lower_bound              // 1st occurence greater equal to x
#define ub upper_bound              // 1st occurence greater than x 
#define mxe *max_element            // maximum element
#define mne *min_element            // minimum element
#define isr is_sorted               // checks if segment is sorted
#define all(x) x.begin(),x.end()
#define ve vector
#define pll pair<ll,ll>             // pair<ll,ll>
#define vll ve<ll>                  // vector<ll>
#define vvll ve<vll>                // vector<vector<ll>>   
#define vpll ve<pll>                // vector<pair<ll,ll>>
#define vvpll ve<vpll>              // vector<vector<pair<ll,ll>>>

#ifndef gdb_18
#define endl '\n'                   // do not use for interactive problems , not use assert
#endif

/*---------------------------------- RANDOM NUMBER GENERATOR ------------------------------*/

auto random_address = [] { char *p = new char; delete p; return ull(p); };
const ull SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1);
mt19937_64 rng(SEED);

inline i64 rnd(ll l = LLONG_MIN , ll r = LLONG_MAX)
{
    uniform_int_distribution<i64> generator(l,r);
    return generator(rng);
}

/*------------------------------------------- I/O -----------------------------------------*/

// Credits: Template of user kal013

istream& operator >> (istream &is, i128& T)
{
    static char buffer[64];
    is >> buffer;
    size_t len = strlen(buffer), index = 0;
    T = 0; int mul = 1;
    if (buffer[index] == '-')
        ++index, mul *= -1;
    for(; index < len; ++index)
        T = T * 10 + static_cast<int>(buffer[index] - '0');
    T *= mul;    
    return is;
}

ostream& operator << (ostream &os, i128 const& value)
{
    static char buffer[64];
    int index = 0;
    u128 T = (value < 0) ? (-(value + 1)) + u128(1) : value;
    if (value < 0) 
        os << '-';
    else if (T == 0)
        return os << '0';
    for(; T > 0; ++index){
        buffer[index] = static_cast<char>('0' + (T % 10));
        T /= 10;
    }    
    while(index > 0)
        os << buffer[--index];
    return os;
}

template<class T> istream& operator >> (istream &is, ve<T>& V) 
{
    for(auto &it : V)
        is >> it;
    return is;
}

template<class T> ostream& operator << (ostream &os, ve<T> V) 
{
    for(auto it : V) 
        os << it << " ";
    return os << "";
}

template<class L, class R> istream& operator >> (istream &is, pair<L,R>& P) 
{
    return is >> P.first >> P.second;
}

template<class L, class R> ostream& operator << (ostream &os, pair<L,R> P) 
{
    return os << P.first << " " << P.second;
}

template<class L, class R> ostream& operator << (ostream &os, map<L,R> M) 
{
    os << "{ ";
    for(auto it : M) 
        os << "(" << it.first << ":" << it.second << ") ";
    return os << "}";
}

template<class T> ostream& operator << (ostream &os, set<T> S)
{
    for(auto it : S) 
        os << it << " ";
    return os << "";
}

template<class T> ostream& operator << (ostream &os, multiset<T> S)
{
    for(auto it : S) 
        os << it << " ";
    return os << "";
}

/*----------------------------------------- VECTORS ---------------------------------------*/
/* vll arr; arr.resize(n); --> to resize vector to size n */
/* vll arr; arr=vll(n,0); --> to initialise vector */
/* to copy a vector -> vll arr; vll arr1; arr1=arr; or vll arr1(arr); */
/* to create merge sort tree --> stl merge function */
/* merge(all(arr1),all(arr2),arr3.begin()) --> resize arr3 first */
/* merge(all(arr1),all(arr2),back_inserter(arr3)) --> do not resize arr3 ,it adds at end */

/*------------------------------------------- MAPS ----------------------------------------*/
/* map<ll,ll> temp --> insert(mp(a,b)) , size() , empty() , clear() */
/* find(key) returns end() if not found */
/* temp.lower_bound(x) --> for sets and maps */

/*-------------------------------------- PRIORITY QUEUE -----------------------------------*/
#define pqueue priority_queue
/* pqueue<ll> temp --> max heap , pqueue<ll,vll,greater<ll>> temp --> min heap */
/* temp.push() , temp.top() , temp.pop() , temp.size() , temp.empty() */

/*------------------------------------ SETS AND MULTISETS ---------------------------------*/
/* insert() , size() , empty() , lower_bound , upper_bound */
/* temp.lower_bound(x) --> for sets and maps */
/* find(x) iterator to x if exists else end() */
/* erase() deletes element or iterator in set, ALL elements or a iterator in multiset */
/* FIND & ERASE WORK ON ORDERED SETS BUT NOT ON ORDERED MULTISETS */
template<class T> 
using oset = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
/* less<T> --> set , less_equal<T> --> multiset for increasing order */
/* greater<T> --> set , greater_equal<T> --> multiset for decreasing order */
#define fbo find_by_order 
#define ook order_of_key
/* find_by_order(x) - iterator to xth element (0 indexed) if exists else returns end() */
/* increasing order: order_of_key(x) - number of items strictly lesser than x */
/* decreasing order: order_of_key(x) - number of items strictly greater than x */

template<class T> ostream& operator << (ostream &os, oset<T> S)
{
    for(auto it : S) 
        os << it << " ";
    return os << "";
}

/*--------------------------------- STACKS QUEUES AND DEQUES ------------------------------*/
#define pb push_back
#define ppb pop_back()
#define pf push_front
#define ppf pop_front()
/* size() , empty() works for all but clear() works for deque only */
/* stack<ll> --> push() , top() , pop() */
/* queue<ll> --> push() , pop() , front() , back() */
/* deque<ll> --> push_front() , push_back() , pop_front() ,pop_back() , front() , back() */

/*--------------------------------- CONSTANTS AND FUNCTIONS -------------------------------*/
const ll modulo1=1e9+7;
const ll modulo2=998244353;
const ll inf=1e18;
const ld pi=acos(-1);
const ld eps=1e-7;
inline ll power(ll a,ll b,ll m)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=(res*a)%m; 
        a=(a*a)%m; b>>=1;
    }
    return res%m;
}
inline ll inv(ll a,ll m)
{
    return power(a,m-2,m);
}

/*-------------------------------------- CODE BEGINS --------------------------------------*/

const ll N=5e5+5;
const ll M=5e2+5;       
ll mod=modulo1;                 

vvpll adj(N);
ve<ve<pair<ll,pll>>> que(N);
vll ans(N);
ll dist[N];

struct dat{
    //Required Attributes
    ll mn;
    ll lazy;

    //Default Initialization
    dat(){
        mn = inf;
        lazy = 0;
    }
};

struct lazy_segtree{
    int n;
    vector<dat> v;
    lazy_segtree(int n):n(n){
        v.resize(4*n+5);
    }

    /////////////Have to Change This//////////////////
    void merge(dat &x, dat &y, dat &z){
        x.mn = min(y.mn, z.mn);
    }


    /////////////Have to Change This//////////////////
    void lazy_update(int x, int l, int r){
        if(l!=r){
            v[2*x].lazy += v[x].lazy;
            v[2*x+1].lazy += v[x].lazy;
        }
        v[x].mn = v[x].mn + v[x].lazy;
        v[x].lazy = 0;
        return;
    }


    void build(int l, int r, int x){
        if(l==r){
            v[x] = dat();
            return;
        }
        int m = (l+r)/2;
        build(l,m,2*x);
        build(m+1,r,2*x+1);
        merge(v[x],v[2*x],v[2*x+1]);
    }
    void build(){
        build(1,n,1);
    }


    void update(int l, int r, int pos1, int pos2, ll val, int x)
    {
        lazy_update(x,l,r);
        if(l>pos2 || r<pos1)
            return;
        if(l>=pos1 && r<=pos2){
            /////////////Have to Change This//////////////////
            v[x].lazy += val;
            lazy_update(x,l,r);
            return;
        }
        int m = (l+r)/2;
        update(l,m,pos1,pos2,val,2*x);
        update(m+1,r,pos1,pos2,val,2*x+1);
        merge(v[x],v[2*x],v[2*x+1]);
        return;
    }
    void update(int pos1, int pos2, ll val)
    {
        update(1,n,pos1,pos2,val,1);
        return;
    }


    dat query(int l, int r, int l1, int r1, int x)
    {
        lazy_update(x,l,r);
        if(l>r1 || r<l1){
            return dat();
        }
        if(l>=l1 && r<=r1){
            return v[x];
        }
        dat ans=dat();
        int m = (l+r)/2;
        dat left = query(l,m,l1,r1,2*x);
        dat right = query(m+1,r,l1,r1,2*x+1);
        merge(ans,left,right);
        return ans;
    }

    dat query(int l, int r)
    {
        return query(1,n,l,r,1);
    }
};


lazy_segtree solver(N);

void dfs(ll v,ll tt)
{
    ll cnt=0;
    for(auto it:adj[v])
    {
        dfs(it.ff,tt+it.ss);
        cnt++;
    }
    if(cnt)
        dist[v]=1e14;
    else
        dist[v]=tt;
    return;
}

// Snippet for flattening the tree
// Requires: vvll adj(N)
vll stime(N,0);
vll etime(N,0);
vll vertex(N,0);
vll size_of_subtree(N,0);
vll depth_of_node(N,1);
vll height_of_node(N,1);
ll timer_to_flatten_tree=0;
void flatten_tree(ll v , ll p = -1)
{
    size_of_subtree[v]=1;
    timer_to_flatten_tree++;
    stime[v]=timer_to_flatten_tree;
    vertex[timer_to_flatten_tree]=v;
    ll mx=0;
    for(auto it:adj[v])
        if(it.ff!=p)
        {
            depth_of_node[it.ff]+=depth_of_node[v];
            flatten_tree(it.ff,v);
            size_of_subtree[v]+=size_of_subtree[it.ff];
            mx=max(mx,height_of_node[it.ff]);
        }
    height_of_node[v]+=mx;
    etime[v]=timer_to_flatten_tree;
    return;
}


void dfs1(ll v,ll rg)
{
    for(auto i:que[v])
    {
        ll l=i.ss.ff;ll r=i.ss.ss;
        ans[i.ff]=solver.query(l,r).mn;
    }
    for(auto it:adj[v])
    {
        ll ct=it.ss;
        // upd
        ll te=it.ff;
        solver.update(stime[te],etime[te],(-1*ct));
        solver.update(1,stime[te]-1,ct);
        solver.update(etime[te]+1,rg,ct);
        dfs1(te,rg);
            solver.update(stime[te],etime[te],(ct));
        solver.update(1,stime[te]-1,(-1*ct));
        solver.update(etime[te]+1,rg,(-1*ct));
    }
    return;
}

void solve()
{
    ll n,q;
    cin>>n>>q;
    for(ll i=2;i<=n;i++)
    {
        ll x,y;
        cin>>x>>y;
        adj[x].pb({i,y});
    }
    for(ll i=0;i<q;i++)
    {
        ll a,b,c;
        cin>>a>>b>>c;
        que[a].pb({i,{b,c}});
    }
    dfs(1,0);
    flatten_tree(1,-1);
    solver.build();
    for(ll i=1;i<=n;i++)
    {
        // cout<<dist[i]<<endl;
        solver.update(i,i,dist[i]-inf);
    }
// for(ll i=1;i<=n;i++)
//     {
//         // cout<<dist[i]<<endl;
//         cout<<solver.query(i,i).mn<<endl;
//     }

    dfs1(1,n);
    for(ll i=0;i<q;i++)
        cout<<ans[i]<<endl;
   return; 
}

void precompute()
{
    // cout<<fixed<<setprecision(10);
    return;
}

/*--------------------------------------- CODE ENDS ---------------------------------------*/
signed main()
{
    clock_t clk=clock();
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    #ifdef gdb_18
        freopen("input.txt","rt",stdin);
        freopen("output.txt","wt",stdout);
    #endif
    precompute();
    ll test=1;
    // cin>>test;
    for(ll i=1;i<=test;i++)
    {
        // cout<<"Case #"<<i<<": ";
        // cout<<endl;
        solve();
    }
    #ifdef gdb_18
    cerr<<"Execution Time : "<<(1000.0*((ld)(clock()-clk))/(ld)CLOCKS_PER_SEC)<<"ms\n";
    #endif
    return 0;   
}
/*-----------------------------------------------------------------------------------------*/

// Snippet for kmp
// Credits : https://cp-algorithms.com/string/prefix-function.html
// vll prefix_function(string s) 
// {
//     ll n=(ll)s.length();
//     vll lps(n);
//     for (ll i=1;i<n;i++) 
//     {
//         ll j=lps[i-1];
//         while (j>0 && s[i]!=s[j])
//             j=lps[j-1];
//         if (s[i]==s[j])
//             j++;
//         lps[i]=j;
//     }
//     return lps;
// }


// Snippet for flattening the tree
// Requires: vvll adj(N)
// vll stime(N,0);
// vll etime(N,0);
// vll vertex(N,0);
// vll size_of_subtree(N,0);
// vll depth_of_node(N,1);
// vll height_of_node(N,1);
// ll timer_to_flatten_tree=0;
// void flatten_tree(ll v , ll p = -1)
// {
//     size_of_subtree[v]=1;
//     timer_to_flatten_tree++;
//     stime[v]=timer_to_flatten_tree;
//     vertex[timer_to_flatten_tree]=v;
//     ll mx=0;
//     for(auto it:adj[v])
//         if(it!=p)
//         {
//             depth_of_node[it]+=depth_of_node[v];
//             flatten_tree(it,v);
//             size_of_subtree[v]+=size_of_subtree[it];
//             mx=max(mx,height_of_node[it]);
//         }
//     height_of_node[v]+=mx;
//     etime[v]=timer_to_flatten_tree;
//     return;
// }


// Snippet for dsu on tree
// Requires: Snippet for flattening the tree
// void dsu_on_tree(ll v,ll p,bool kp)
// {
//     ll bigchild=-1,mx=-1;
//     for(auto it:adj[v])
//     {
//         if(it!=p)
//         {
//             if(size_of_subtree[it]>mx)
//             {
//                 mx=size_of_subtree[it];
//                 bigchild=it;
//             }
//         }
//     }
//     for(auto it:adj[v])
//         if(it!=p && it!=bigchild)
//             dsu_on_tree(it,v,0);
//     if(bigchild!=-1)
//         dsu_on_tree(bigchild,v,1);
//     for(auto it:adj[v])
//     {
//         if(it!=p && it!=bigchild)
//         {
//             for(ll i=stime[it];i<=etime[it];i++)
//             {
//                 // make changes for subtrees of smallchilds vertex[i]
//             }
//         }
//     }
//     // make changes for current vertex v   
//     // answer queries for current vertex v here
//     if(kp==0)
//     {
//         for(ll i=stime[v];i<=etime[v];i++)
//         {
//             // make changes for subtree of current vertex v
//         }
//     }
//     return;
// }

// Snippet for sieve
// ve<bool> ipr;
// vll pr;
// void sieve(ll n)
// {
//     ipr.resize(n+1, true);
//     ipr[0] = ipr[1] = false;
//     for (ll i = 2; i * i <= n; i++) 
//         if (ipr[i]) 
//              for (ll j = i * i; j <= n; j += i)
//                 ipr[j] = false;
//     for(ll i=2;i<=n;i++)
//         if(ipr[i])
//             pr.pb(i);
//     return;
// }

// Snippet for factorisation
// vpll factorisation(ll n) 
// {
//     vpll xx;
//     for (ll i = 2; i * i <= n; i++) 
//     {
//         ll cnt=0;
//         while (n % i == 0) {
//             cnt++;
//             n /= i;
//         }
//         if(cnt)
//             xx.pb({i,cnt});
//     }
//     if (n > 1)
//         xx.pb({n,1});
//     return xx;
// }

// Snippet for checking prime 
// u64 binpower(u64 base, u64 e, u64 mod) {
//     u64 result = 1;
//     base %= mod;
//     while (e) {
//         if (e & 1)
//             result = (u128)result * base % mod;
//         base = (u128)base * base % mod;
//         e >>= 1;
//     }
//     return result;
// }
// bool check_composite(u64 n, u64 a, u64 d, int s) {
//     u64 x = binpower(a, d, n);
//     if (x == 1 || x == n - 1)
//         return false;
//     for (int r = 1; r < s; r++) {
//         x = (u128)x * x % n;
//         if (x == n - 1)
//             return false;
//     }
//     return true;
// }
// bool is_prime(u64 n) { 
//     if (n < 2)
//         return false;
//     int r = 0;
//     u64 d = n - 1;
//     while ((d & 1) == 0) {
//         d >>= 1;
//         r++;
//     }
//     for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
//         if (n == a)
//             return true;
//         if (check_composite(n, a, d, r))
//             return false;
//     }
//     return true;
// }

// Snippet for flow
// struct FlowEdge
// {
//     ll u,v,capacity,flow=0;
//     FlowEdge(ll x,ll y,ll z)
//     {
//         u=x;
//         v=y;
//         capacity=z;
//     }
// };
// struct Dinic
// {
//     ll n,m,source,sink;
//     vvll adj;
//     ve<FlowEdge> edges;
//     vll level,ptr;
//     queue<ll> temp;
//     Dinic(ll vertices,ll src,ll snk)
//     {
//         n=vertices;
//         m=0;
//         source=src;
//         sink=snk;
//         adj.resize(n+5);
//         level.resize(n+5);
//         ptr.resize(n+5);
//     }
//     void addEdge(ll x,ll y,ll cap)
//     {
//         FlowEdge a(x,y,cap),b(y,x,0LL);
//         edges.pb(a);
//         edges.pb(b);
//         adj[x].pb(m);
//         adj[y].pb(m+1);
//         m+=2;
//         return;
//     }
//     bool bfs()
//     {
//         while(!temp.empty())
//         {
//             ll cur=temp.front();
//             temp.pop();
//             for(auto i:adj[cur])
//             {
//                 if(edges[i].capacity-edges[i].flow <= 0)
//                     continue;
//                 if(level[edges[i].v] != -1)
//                     continue;
//                 level[edges[i].v]=level[cur]+1;
//                 temp.push(edges[i].v);
//             }
//         }
//         return (level[sink] != -1);
//     }
//     ll dfs(ll cur,ll flow_of_path)
//     {
//         if(flow_of_path==0)
//             return 0;
//         if(cur==sink)
//             return flow_of_path;
//         for(ll &i=ptr[cur];i<adj[cur].size();i++)
//         {
//             ll id=adj[cur][i];
//             ll v=edges[id].v;
//             if(level[v]!=level[cur]+1 || edges[id].capacity-edges[id].flow <= 0)
//                 continue;
//             ll new_flow=dfs(v,min(flow_of_path,edges[id].capacity-edges[id].flow));
//             if(new_flow==0)
//                 continue;
//             edges[id].flow+=new_flow;
//             edges[id^1].flow-=new_flow;
//             return new_flow;
//         }
//         return 0;
//     }
//     ll find_flow()
//     {
//         ll ans=0;
//         while(1)
//         {
//             fill(all(level),-1);
//             level[source]=0;
//             temp.push(source);
//             if(!bfs())
//                 break;
//             fill(all(ptr),0);
//             while(ll blocking_flow=dfs(source,inf))
//                 ans+=blocking_flow;
//         }
//         return ans;
//     }
// };


// ToDo: dijkstra, dfs, bfs, dsu, segment trees, fft, 
// lca,sparse table, binary lifting  .... 