/*  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=1e3+5;       
ll mod=modulo1;                 

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

// Snippet for polynomial segment tree
struct polynomial
{
    // If need be add more terms
    ll c3,c2,c1,c0;     // (c3 . x^3) + (c2 . x^2) + (c1 . x) + (c0)
    void init(ll x3 = 0,ll x2 = 0,ll x1 = 0,ll x0 = 0) 
    {
        c3=x3;
        c2=x2;
        c1=x1;
        c0=x0;
        return;
    }
    void shift(ll o)
    {
        c3 = (c3);
        c2 = (c2) + (3 * c3 * o);
        c1 = (c1) + (2 * c2 * o) + (3 * c3 * o * o);
        c0 = (c0) + (1 * c1 * o) + (1 * c2 * o * o) + (1 * c3 * o * o * o);
        return;
    }
    void add(polynomial x)
    {
        c3 += x.c3;
        c2 += x.c2;
        c1 += x.c1;
        c0 += x.c0;
        return;
    }
    ll val(ll x)
    {
        ll sum0= (c0) * (x);
        ll sum1= (c1) * (x) * (x+1) / 2;
        ll sum2= (c2) * (x) * (x+1) * (2*x + 1) / 6;
        ll sum3= (c3) * (x) * (x+1) * (x) * (x+1) / 4;
        ll sum = sum0 + sum1 + sum2 + sum3;
        return sum;
    }
};

struct PolynomialSegmentTree
{
    ll st,en,n;
    vll arr,Tree;
    ve<polynomial> lazy;
    
    ll merge(ll a,ll b)
    {
        ll temp;
        // write merge function
        temp=min(a,b);

        return temp;
    }

    void build(ll t,ll tl,ll tr)
    {
        lazy[t].init();
        if(tl==tr)
        {
            Tree[t]=arr[tl];
            return;
        }
        ll tm=(tl+tr)/2;
        build(2*t,tl,tm);
        build(2*t+1,tm+1,tr);
        Tree[t]=merge(Tree[2*t],Tree[2*t+1]);
        return;
    }

    PolynomialSegmentTree(vll ar) // give array as vll 
    {
        n=ar.size();
        st=0;
        en=n-1;
        arr.resize(n);
        for(ll i=0;i<n;i++)
            arr[i]=ar[i];
        Tree.resize(4*n+5);
        lazy.resize(4*n+5);
        build(1,st,en);
    }

    PolynomialSegmentTree(ll sz,ll def_value)  // give size,value 
    {
        n=sz;
        st=0;
        en=n-1;
        arr.resize(n);
        for(ll i=0;i<n;i++)
            arr[i]=def_value;
        Tree.resize(4*n+5);
        lazy.resize(4*n+5);
        build(1,st,en);
    }

    void push(ll t,ll tl,ll tr)
    {
        ll tm=(tl+tr)/2;
        Tree[2*t]+=lazy[t].val(tm-tl+1);
        lazy[2*t].add(lazy[t]);
        lazy[t].shift(tm-tl+1);
        Tree[2*t+1]+=lazy[t].val(tr-tm);
        lazy[2*t+1].add(lazy[t]);
        lazy[t].init();
        return;
    }
     
    void update(ll t,ll tl,ll tr,ll l,ll r,polynomial x)
    {
        if(l>r)
            return;
        if(tl==l && tr==r)
        {
            Tree[t]+=x.val(r-l+1);
            lazy[t].add(x);
            return;
        }
        push(t,tl,tr);
        ll tm=(tl+tr)/2;
        update(2*t,tl,tm,l,min(r,tm),x);
        x.shift(max(0LL,min(r,tm)-l+1));
        update(2*t+1,tm+1,tr,max(l,tm+1),r,x);
        Tree[t]=merge(Tree[2*t],Tree[2*t+1]);
        return;
    }
     
    void update(ll l,ll r,polynomial to_be_added)
    {
        update(1,st,en,l,r,to_be_added);
        return;
    }

    ll query(ll t,ll tl,ll tr,ll l,ll r)
    {
        // check what is to be returned here
        if(l>r)
            return inf;
        if(tl==l && tr==r)
            return Tree[t];
        push(t,tl,tr);
        ll tm=(tl+tr)/2;
        return merge(query(2*t,tl,tm,l,min(r,tm)),query(2*t+1,tm+1,tr,max(l,tm+1),r));
    }

    ll query(ll l,ll r)
    {
        return query(1,st,en,l,r);
    }
};



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]=inf;
    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,PolynomialSegmentTree &solver)
{
    for(auto i:que[v])
    {
        ll l=i.ss.ff;ll r=i.ss.ss;
        ans[i.ff]=solver.query(l,r);
    }
    for(auto it:adj[v])
    {
        ll ct=it.ss;
        // upd
        ll te=it.ff;
        polynomial p1,p2;
        p1.init(0,0,0,(-1*ct));
        p2.init(0,0,0,ct);
        solver.update(stime[te],etime[te],p1);
        solver.update(1,stime[te]-1,p2);
        solver.update(etime[te]+1,rg,p2);
        dfs1(te,rg,solver);
        solver.update(stime[te],etime[te],p2);
        solver.update(1,stime[te]-1,p1);
        solver.update(etime[te]+1,rg,p1);
    }
    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);
    PolynomialSegmentTree solver(dist);
    dfs1(1,n,solver);
    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;   
}
/*-----------------------------------------------------------------------------------------*/



