#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define int ll
int n, k = 1;

// #undef DEBUG
// #define DEBUG
/// {{{ DEBUG --- ///
#ifdef DEBUG
template <typename T> ostream &operator<<(ostream &o, const vector<T> &v) { o << "{"; for(size_t i = 0; i < v.size(); i++) o << v[i] << (i + 1 != v.size() ? ", " : ""); o << "}"; return o; }
#ifdef USE_COUT
#define dump(...) [&](){auto __debug_tap=make_tuple(__VA_ARGS__);cout<<"["<<__LINE__<< "] "<<#__VA_ARGS__<<" = "<<__debug_tap<<"\n";}()
#else
#define dump(...) [&](){auto __debug_tap=make_tuple(__VA_ARGS__);cerr<<"["<<__LINE__<< "] "<<#__VA_ARGS__<<" = "<<__debug_tap<<"\n";}()
#endif
template<class T> inline void dump2D(T &d, size_t sizey, size_t sizex) { ostream&o=
#ifdef USE_COUT
  cout;
#else
  cerr;
#endif
  for(size_t i = 0; i < sizey; i++) { for(size_t j = 0; j < sizex; j++) o << d[i][j] << " "; o << endl; }
}
#else
template <typename T> ostream &operator<<(ostream &o, const vector<T> &v) { for(size_t i = 0; i < v.size(); i++) o << v[i] << (i + 1 != v.size() ? " " : ""); return o; }
#define dump(...) (42)
#define dump2D(...) (42)
#endif
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":", ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream &o, tuple<T...> const &t){ o << "("; _ot<0>(o, t); o << ")"; return o; }
template<class T, class U> ostream & operator<<(ostream &o, pair<T, U> const &p) { o << "(" << p.first << ", " << p.second << ")"; return o; }
/// }}}--- ///


// NOTE : query in range!
/// --- SegmentTree Library {{{ ///

// struct Monoid {
//   using T = _underlying_set_;
//   static T op(const T& a, const T& b) { return _a_op_b_; }
//   static constexpr T identity() { return _identity_element_; }
// };

template<class Monoid>
struct SegTree {
private:
  using T = typename Monoid::T;
  int n;
  std::vector<T> data;
  // call after touch data[i]
  void prop(int i) { data[i] = Monoid::op(data[2 * i], data[2 * i + 1]); }
public:
  SegTree(): n(0) {}
  SegTree(int n): n(n) {
    data.resize(n * 2, Monoid::identity());
  }
  template<class InputIter, class = typename std::iterator_traits<InputIter>::value_type>
    SegTree(InputIter first, InputIter last)
    : SegTree(std::distance(first, last)) {
      copy(first, last, std::begin(data) + n);
      // fill from deep
      for(int i = n - 1; i > 0; i--) prop(i);
    }
  void set(int i, const T& v) {
    data[i += n] = v;
    while(i >>= 1) prop(i); // propUp
  }
  T get(int i) { return data[i + n]; }
  T query(int l, int r) {
    T tmpL = Monoid::identity(), tmpR = Monoid::identity();
    for(l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if(l & 1) tmpL = Monoid::op(tmpL, data[l++]);
      if(r & 1) tmpR = Monoid::op(data[--r], tmpR);
    }
    return Monoid::op(tmpL, tmpR);
  }
  inline void dum(int r = -1) {
#ifdef DEBUG
    std::ostream & o =
#ifdef USE_COUT
      std::cout
#else
      std::cerr
#endif
      ;
    if(r < 0) r = n;
    o << "{";
    for(int i = 0; i < std::min(r, n); i++) o << (i ? ", " : "") << get(i);
    o << "}" << std::endl;
#endif
  }
};

/// }}}--- ///

// Monoid examples {{{

constexpr long long inf = std::numeric_limits<long long>::max();
// using P = pair<ll, ll>

using P = tuple<int, int, int>;

struct MonoidMin {
  using T = long long;
  static T op(const T& a, const T& b) { return std::min(a, b); }
  static constexpr T identity() { return inf; }
};
struct M{
  using T = P;
  static T op(const T& a, const T& b) {
    int al, ac, ar; tie(al, ac, ar) = a;
    int bl, bc, br; tie(bl, bc, br) = b;
    if(al == -1) return b;
    if(bl == -1) return a;
    ar = ar + bl;
    if(ar % k == 0) ar = 0;
    ac = ac + bc;
    return P(al, ac + ar, br);
  }
  static constexpr T identity() { return P(-1, 0, 0); }
};
struct MonoidMax {
  using T = long long;
  static T op(const T& a, const T& b) { return std::max(a, b); }
  static constexpr T identity() { return -inf; }
};

// }}}
const int N = 1e5;

using RMQ = SegTree<M>;
RMQ qina(N);


// query(hi, lo, func, inclusive?)
// hld[i] : index on sequence
// WARN : build after adding edges!
/// --- HL-Decomposition Library {{{ ///

struct HLD {
  int n;
  vector<int> head;
  vector<int> sz;
  vector<int> dep;
  vector<int> par;
  vector<int> vid;
  int id = 0;
  vector< vector<int> > g; // tree
  HLD(int n): n(n), head(n), sz(n), dep(n), par(n), vid(n), g(n) {}
  HLD(vector< vector<int> > g, int root = 0): HLD(g.size()) { this->g = g; build(root); }
  int operator[](int i) { return vid[i]; }
  void addEdge(int a, int b) {
    g[a].emplace_back(b);
    g[b].emplace_back(a);
  }
  void build(int root = 0) {
    head[root] = root;
    dfs0(root, -1, 0); dfs1(root, -1);
  }
  int lca(int a, int b) {
    while(1) {
      if(vid[a] > vid[b]) swap(a, b);
      if(head[a] == head[b]) return a;
      b = par[head[b]];
    }
  }
  void query(int hi, int lo, function<void(int, int)> f, bool inclusive = true) {
    while(lo != -1 && dep[lo] >= dep[hi]) {
      int nex = max(vid[head[lo]], vid[hi]);
      f(nex + (nex == vid[hi] && !inclusive), vid[lo] + 1);
      lo = par[head[lo]];
    }
  }
private:
  void dfs0(int i, int p, int d) {
    par[i] = p;
    sz[i] = 1;
    dep[i] = d;
    for(int &j : g[i]) if(j != p) {
      dfs0(j, i, d + 1);
      sz[i] += sz[j];
      if(sz[j] > sz[g[i][0]]) {
        swap(g[i][0], j);
      }
    }
  }
  void dfs1(int i, int p) {
    vid[i] = id++;
    for(int j : g[i]) if(j != p) {
      head[j] = j == g[i][0] ? head[i] : j;
      dfs1(j, i);
    }
  }
};

/// }}}--- ///

vector<pair<int, int>> g[N];
HLD ecas(N);
vector<int> cost(N);

void dfs(int i, int p = -1) {
  // dump(i, p);
  for(auto to:g[i]) {
    int j, c; tie(j, c) = to;
    if(j == p) continue;
    ecas.addEdge(i, j);
    cost[j] = c;
    dfs(j, i);
  }
}

signed main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> n>>k;
  for(int i = 0; i < n-1; i++) {
    int a,b,c;
    cin >> a >> b >> c;
    g[a].emplace_back(b, c);
    g[b].emplace_back(a, c);
  }
  dfs(0, -1);
  ecas.build();
  for(int i = 0; i < n; i++) dump(i, ecas[i], cost[i]), qina.set(ecas[i], P(cost[i], 0, 0));
  int q;
  cin >> q;
  for(int i = 0; i < q; i++) {
    string s;
    cin >> s;
    if(s[0] == 'a') { // add
      int x, d;
      cin >> x >> d;
      auto p = qina.get(ecas[x]);
      get<0>(p)+=d;
      get<2>(p)+=d;
      qina.set(ecas[x], p);
    } else {
      int s, t; cin >> s >> t;
      int lca = ecas.lca(s, t);
      ll res = 0;
      P tmp;
      auto f = [&](int l, int r) {
        tmp = M::op(qina.query(l, r), tmp);
      };

      tmp = P(-1, 0, 0);
      ecas.query(lca, s, f, 1);
      res += get<1>(tmp);
      dump(res);

      tmp = P(-1, 0, 0);
      ecas.query(lca, t, f, 1);
      res += get<1>(tmp);
      dump(lca);
      cout << res << endl;
    }
  }
  return 0;
}



Measured memory_bytes: 34300