#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;
#define ordered_set <int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>
#define ordered_multiset <int, null_type, less_equal <int>, rb_tree_tag, tree_order_statistics_node_update>
#define int long long
#define double long double
#define pii pair <int, int>
#define tiii tuple <int, int, int>
#define tiiii tuple <int, int, int, int>
#define emb emplace_back
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define iShowSpeed cin.tie(NULL)->sync_with_stdio(false)
#define matrix vector <vector <int>>
#define mat(n, m) vector <vector <int>> (n, vector <int> (m));
const int mod = 1e9 + 7;
const int inf = 1e18;
const matrix II = {{1, 0}, {0, 1}};
const int N = 1e5 + 5;
const int LG = 20;
int n, q, on[N], sz[N], par[N], depth[N], realdepth[N], tin[N], tout[N], t, dis[LG][N];
bool visited[N];
vector <pii> adj[N], idx[N];
struct segment {
int sz;
vector <int> seg, dis, lazy;
segment() : sz(0) {}
void push(int l, int r, int i){
if (seg[i] != inf) seg[i] += lazy[i];
dis[i] += lazy[i];
if (l != r) lazy[2 * i] += lazy[i], lazy[2 * i + 1] += lazy[i];
lazy[i] = 0;
}
void build(int l, int r, int i, vector <pii> &node){
if (l == r) return dis[i] = node[l - 1].second, void();
int mid = (l + r) / 2;
build(l, mid, 2 * i, node), build(mid + 1, r, 2 * i + 1, node);
}
void initialize(vector <pii> &node){
sz = node.size();
seg.resize(4 * sz + 5, inf);
dis.resize(4 * sz + 5, inf);
lazy.resize(4 * sz + 5, 0);
build(1, sz, 1, node);
}
void update(int l, int r, int i, int ll, int rr, int val){
push(l, r, i);
if (l >= ll && r <= rr) return lazy[i] += val, push(l, r, i), void();
if (r < ll || l > rr) return;
int mid = (l + r) / 2;
update(l, mid, 2 * i, ll, rr, val), update(mid + 1, r, 2 * i + 1, ll, rr, val);
seg[i] = min(seg[2 * i], seg[2 * i + 1]);
}
void open(int l, int r, int i, int idx) {
push(l, r, i);
if (l == r) return seg[i] = dis[i], void();
int mid = (l + r) / 2;
if (idx <= mid) open(l, mid, 2 * i, idx);
else open(mid + 1, r, 2 * i + 1, idx);
seg[i] = min(seg[2 * i], seg[2 * i + 1]);
dis[i] = min(dis[2 * i], dis[2 * i + 1]);
}
void close(int l, int r, int i, int idx){
push(l, r, i);
if (l == r) return seg[i] = inf, void();
int mid = (l + r) / 2;
if (idx <= mid) close(l, mid, 2 * i, idx);
else close(mid + 1, r, 2 * i + 1, idx);
seg[i] = min(seg[2 * i], seg[2 * i + 1]);
dis[i] = min(dis[2 * i], dis[2 * i + 1]);
}
int query(int l, int r, int i, int idx) {
push(l, r, i);
if (l == r) return dis[i];
int mid = (l + r) / 2;
if (idx <= mid) return query(l, mid, 2 * i, idx);
return query(mid + 1, r, 2 * i + 1, idx);
}
};
segment seg[N];
void dfs1(int u, int p){
tin[u] = ++t;
realdepth[u] = realdepth[p] + 1;
for (auto [w, v] : adj[u]) {
if (v == p || visited[v]) continue;
dfs1(v, u);
}
tout[u] = t;
}
int dfssz(int u, int p){
sz[u] = 0;
for (auto [w, v] : adj[u]) {
if (v == p || visited[v]) continue;
sz[u] += dfssz(v, u);
}
return ++sz[u];
}
int centroid(int u, int p, int szz){
for (auto [w, v] : adj[u]) {
if (v == p || visited[v]) continue;
if (2 * sz[v] > szz) return centroid(v, u, szz);
}
return u;
}
void dfs(int u, int p, int dist, vector <pii> &node){
node.emb(tin[u], dist);
for (auto [w, v] : adj[u]) {
if (v == p || visited[v]) continue;
dfs(v, u, dist + w, node);
}
}
void decompose(int u, int p){
int c = centroid(u, u, dfssz(u, u));
par[c] = p;
visited[c] = 1;
depth[c] = depth[p] + 1;
dfs(c, c, 0, idx[c]);
sort(all(idx[c]));
seg[c].initialize(idx[c]);
for (auto [w, v] : adj[c]) if (!visited[v]) decompose(v, c);
}
map <pii, int> edge;
void update(int u, int v, int w){
int dif = w - edge[{u, v}];
edge[{u, v}] = edge[{v, u}] = w;
if (realdepth[u] > realdepth[v]) swap(u, v);
int cur = (depth[u] < depth[v] ? u : v);
while (cur) {
int ll = lower_bound(all(idx[cur]), make_pair(tin[v], -1ll)) - idx[cur].begin() + 1;
int rr = upper_bound(all(idx[cur]), make_pair(tout[v], inf)) - idx[cur].begin();
if (tin[v] <= tin[cur] && tout[cur] <= tout[v]) {
if (ll > 1) seg[cur].update(1, seg[cur].sz, 1, 1, ll - 1, dif);
if (rr < seg[cur].sz) seg[cur].update(1, seg[cur].sz, 1, rr + 1, seg[cur].sz, dif);
}
else seg[cur].update(1, seg[cur].sz, 1, ll, rr, dif);
cur = par[cur];
}
}
void open(int u){
int v = u;
while (v) {
int idxx = lower_bound(all(idx[v]), make_pair(tin[u], -1ll)) - idx[v].begin() + 1;
seg[v].open(1, seg[v].sz, 1, idxx);
v = par[v];
}
}
void close(int u){
int v = u;
while (v) {
int idxx = lower_bound(all(idx[v]), make_pair(tin[u], -1ll)) - idx[v].begin() + 1;
seg[v].close(1, seg[v].sz, 1, idxx);
v = par[v];
}
}
int query(int u){
int v = u;
int ans = inf;
while (v) {
int idxx = lower_bound(all(idx[v]), make_pair(tin[u], -1ll)) - idx[v].begin() + 1;
ans = min(ans, seg[v].query(1, seg[v].sz, 1, idxx) + seg[v].seg[1]);
v = par[v];
}
return ans;
}
void solve(){
cin >> n >> q;
for (int i = 1; i < n; i++) {
int u, v, w; cin >> u >> v >> w;
adj[u].emb(w, v);
adj[v].emb(w, u);
edge[{u, v}] = edge[{v, u}] = w;
}
dfs1(1, 1);
decompose(1, 0);
while (q--) {
int t; cin >> t;
if (t == 2) {
int u; cin >> u;
if (on[u]) on[u] = 0, close(u);
else on[u] = 1, open(u);
}
if (t == 1) {
int u; cin >> u;
int ans = query(u);
cout << (ans == inf ? -1ll : ans) << "\n";
}
if (t == 3) {
int u, v, w; cin >> u >> v >> w;
update(u, v, w);
}
}
}
int32_t main(){
iShowSpeed;
// int q; cin >> q; while (q--)
solve();
}