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

using int64 = long long;

struct Edge
{
    int to, cost; Edge () {}
    Edge ( int to, int64 cost ) : to(to), cost(cost) {}
};

struct SegData
{
    int64 c, l, r, e;
    SegData () {} SegData ( int64 c, int64 l, int64 r, int64 e ) : c(c), l(l), r(r), e(e) {}
    bool operator == (const SegData &d) const
    {
        return ( c == d.c && l == d.l && r == d.r && e == d.e );
    }
};

const SegData segId = SegData(0LL, 0LL, 0LL, 0LL);

template < typename T >
struct Monoid
{
    T id;
    function < T(T, T) > op;
    Monoid ( T id, function < T(T, T) > op) : id(id), op(op) {}
};

//このセグ木はaddクエリを作っていかないといかんね
template < typename T >
struct SegmentTree
{
    const Monoid < T > monoid;
    vector < T > dat;
    int size;

    SegmentTree ( int n, Monoid < T > monoid ) : monoid(monoid)
    {
        size = 1;
        while ( size < n ) {
            size *= 2;
        }
        dat.assign(size * 2, monoid.id);
    }

    void update ( int k, T x )
    {
        k += size - 1;
        dat[k] = x;
        while ( k > 0 ) {
            k = (k - 1) / 2;
            dat[k] = monoid.op(dat[k * 2 + 1], dat[k * 2 + 2]);
        }
    }

    T query ( int a, int b )
    {
        return (query(a, b, 0, 0, size - 1));
    }

    T query ( int a, int b, int k, int l, int r )
    {
        T vl, vr;
        if ( r < a || b < l ) return ( monoid.id );
        if ( a <= l && r <= b ) return ( dat[k] );
        vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
        vr = query(a, b, k * 2 + 2, (l + r) / 2 + 1, r);
        return ( monoid.op(vl, vr) );
    }
};

int N;
int64 K;
int Q;
vector < Edge > UG[100005], G[100005];
bool flag[100005] = {};
int size[100005];
int parent[100005][20];
int64 pcost[100005] = {};
int depth[100005];
pair < int , int > liIdx[100005];
int64 _real[100005] = {}; //実際に加算されるやつ(headのみ)
int64 image[100005] = {}; //加算すべきデータ(headがくっつくやつ)
vector < vector < int > > hldNode;
vector < SegmentTree < SegData > > trees;

void makeDirectedGraph ( int sv );
void getGraphSize ( int sv );
void initHLD ( int sv );
void segTreeConstruction();
void doubling();
void makeList();
int lca ( int a, int b );
void add ( int x, int64 d );
int64 send ( int s, int t );
int64 getSendCost ( int tg, int rt );

SegData segOP(SegData a, SegData b)
{
    if ( a == segId ) {
        return ( b );
    } else if ( b == segId ) {
        return ( a );
    } else {
        SegData p;
        int64 cost = a.r + b.l + b.e;
        p.l = a.l, p.e = a.e, p.r = b.r;
        p.c = a.c + b.c + (cost % K > 0 ? cost : 0);
        return ( p );
    }
}

int main()
{
    cin >> N >> K;
    for ( int i = 0; i < N - 1; i++ ) {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        UG[a].push_back(Edge(b, c));
        UG[b].push_back(Edge(a, c));
    }

    flag[0] = true; makeDirectedGraph(0); // 0 : 根
    parent[0][0] = 0; //根は同じノード

    getGraphSize(0);
    initHLD(0);

    segTreeConstruction();
    doubling(); //ダブリング

    //リストのidxを調べよう
    makeList();
    cin >> Q;
    for ( int lp = 0; lp < Q; lp++ ) {
        char S[5];
        scanf("%s", S);
        switch ( S[0] ) {
            case 's':
                int s, t;
                scanf("%d %d", &s, &t);
                printf("%lld\n", send(s, t));
                break;
            case 'a':
                int x, d;
                scanf("%d %d", &x, &d);
                add(x, d);
        }
    }
    return ( 0 );
}

void makeDirectedGraph ( int sv )
{
    using T = pair < int , int >;
    queue < T > que;

    que.emplace(sv, 0);
    while ( !que.empty() ) {
        T d = que.front(); que.pop();
        int v = d.first, dep = d.second;

        depth[v] = dep;

        for ( auto x : UG[v] ) {
            if ( !flag[x.to] ) {
                flag[x.to] = true;
                G[v].emplace_back(x.to, x.cost);
                parent[x.to][0] = v;
                pcost[x.to] = x.cost;
                que.emplace(x.to, dep + 1);
            }
        }
    }
}

void getGraphSize ( int sv )
{
    using T = pair < int , int >;
    stack < T > st;

    st.emplace(0, 0);  //node loop sum

    while ( !st.empty() ) {
        int v, l;
        T d = st.top(); st.pop();

        v = d.first, l = d.second;

        if ( l == 0 ) {
            size[v] = 1;
        } else {
            size[v] += size[G[v][l - 1].to];
        }
        if ( l < G[v].size() ) {
            st.emplace(v, l + 1);
            st.emplace(G[v][l].to, 0);
        }
    }
    return;
}

void initHLD ( int sv )
{
    stack < int > st;

    st.push(sv);
    while ( !st.empty() ) {
        vector < int > node;
        int v = st.top(); st.pop();
        node.push_back(v);
        while ( !G[v].empty() ) {
            int index = -1;
            int maxv = -1;
            for ( auto x : G[v] ) {
                if ( maxv < size[x.to] ) {
                    maxv = size[x.to];
                    index = x.to;
                }
            }
            for ( auto x : G[v] ) {
                if ( index != x.to ) {
                    st.push(x.to);
                }
            }
            v = index;
            node.push_back(v);
        }
        hldNode.push_back(node);
    }
}

void segTreeConstruction()
{
    for ( auto &x : hldNode ) {
        SegmentTree < SegData > temp(x.size(), Monoid < SegData > (segId, segOP));
        for ( int i = 0; i < x.size(); i++ ) {
            auto pushQuery = segId;
            pushQuery.e = pcost[x[i]];
            if ( x[i] == 0 ) {
                pushQuery.l = 1;
            }
            temp.update(i, pushQuery);
        }
        trees.push_back(temp);
    }
}

//parent[node][0]は定義済み
void doubling()
{
    for ( int i = 0; i < 19; i++ ) {
        for ( int v = 0; v < N; v++ ) {
            parent[v][i + 1] = parent[parent[v][i]][i];
        }
    }
}

void makeList()
{
    for ( int i = 0; i < hldNode.size(); i++ ) {
        for ( int j = 0; j < hldNode[i].size(); j++ ) {
            liIdx[hldNode[i][j]] = make_pair(i, j);
        }
    }
}

int lca ( int a, int b )
{
    if ( depth[a] > depth[b] ) {
        swap(a, b);
    }

    //深さを同じにする
    for ( int i = 19; i >= 0; i-- ) {
        if ( ((depth[b] - depth[a]) >> i) & 1 ) {
            b = parent[b][i];
        }
    }

    //すでに同じだったらもう返してあげると嬉しい
    if ( a == b ) {
        return ( a );
    }

    for ( int i = 19; i >= 0; i-- ) {
        if ( parent[a][i] != parent[b][i] ) {
            a = parent[a][i], b = parent[b][i];
        }
    }

    return ( parent[a][0] );
}

void add ( int x, int64 d )
{
    auto idx = liIdx[x];
    auto &target = trees[idx.first];
    auto pushQuery = target.query(idx.second, idx.second);

    image[x] += d;
    pushQuery.l += d, pushQuery.r += d;
    target.update(idx.second, pushQuery);
}

int64 send ( int s, int t )
{
    int rt = lca(s, t);
    return ( getSendCost(s, rt) + getSendCost(t, rt) );
}

int64 getSendCost ( int tg, int rt )
{
    auto idx = liIdx[rt]; //lcaしたところのhl分解後の情報 first : どのセグ木か, second : セグ木の中のどこか
    auto now = liIdx[tg];
    int64 sum = 0;

    int cnt = 0;
    while ( now.first != idx.first ) {
        int cur = hldNode[now.first][0];
        int par = parent[cur][0];
        int64 hokan = image[par] - _real[cur];
        auto &target = trees[now.first];
        auto addQuery = target.query(0, now.second);
        auto pushQuery = target.dat[target.size - 1];
        int64 cost = hokan + addQuery.l + addQuery.e;

        sum += addQuery.c;
        sum += cost % K > 0 ? cost : 0;

        _real[cur] = image[par];

        pushQuery.l += hokan;
        target.update(0, pushQuery);

        now = liIdx[par];
        cnt++;
    }

    //同じ位置になったので後はidxからnowのクエリを処理
    auto &target = trees[now.first];
    auto addQuery = target.query(idx.second, now.second);
    sum += addQuery.c;
    return ( sum );
}



Measured memory_bytes: 49800