// Author: 4uckd3v - Nguyen Cao Duc
#include <bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(), (x).end()
typedef long long ll;
typedef pair<int, int> ii;
const int MAX_N = 1e5;
const int MOD = 1e9 + 7;
const ll INF = 1e18;
struct SegmentTree {
    vector<ll> seg, lazy;
    int n;
    void down(int node) {
        for (int i = 0; i < 2; i++) {
            seg[node << 1 | i] += lazy[node];
            lazy[node << 1 | i] += lazy[node];
        };
        lazy[node] = 0;
    };
    void assign(int pos, ll val) {
        int l = 1, r = n, node = 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (lazy[node]) down(node);
            if (pos <= mid) {
                node <<= 1;
                r = mid;
            } else {
                (node <<= 1) |= 1;
                l = mid + 1;
            };
        };
        seg[node] = val;
        while (node > 1) {
            node >>= 1;
            seg[node] = min(seg[node << 1], seg[node << 1 | 1]);
        };
    };
    void update(int node, int l, int r, int u, int v, int val) {
        if (l > v || r < u) return;
        if (l >= u && r <= v) {
            seg[node] += val;
            lazy[node] += val;
            return;
        };
        int mid = (l + r) >> 1;
        if (lazy[node]) down(node);
        update(node << 1, l, mid, u, v, val);
        update(node << 1 | 1, mid + 1, r, u, v, val);
        seg[node] = min(seg[node << 1], seg[node << 1 | 1]);
    };
    void update(int l, int r, int val) {
        update(1, 1, n, l, r, val);
    };
    ll getMin() {
        return seg[1];
    };
    SegmentTree() {};
    SegmentTree(int n) : n(n) {
        seg.assign(4 * n + 5, INF);
        lazy.assign(4 * n + 5, 0);
    };
};
struct FenwickTree {
    int n;
    vector<ll> bit;
    void update(int pos, int val) {
        for (; pos <= n; pos += pos & (-pos))
            bit[pos] += val;
    };
    ll get(int pos) {
        ll ret = 0;
        for (; pos > 0; pos -= pos & (-pos))
            ret += bit[pos];
        return ret;
    };
    FenwickTree() {};
    FenwickTree(int n) : n(n) {
        bit.assign(n + 5, 0);
    };
};
int n, q, timer, lg;
int par[MAX_N + 5], sz[MAX_N + 5], tin[MAX_N + 5], tout[MAX_N + 5], edgeWeight[MAX_N + 5];
int up[MAX_N + 5][18];
bool del[MAX_N + 5], grap[MAX_N + 5];
ll f[MAX_N + 5];
vector<int> centNode[MAX_N + 5];
vector<ii> adj[MAX_N + 5];
SegmentTree seg[MAX_N + 5];
FenwickTree bit;
void preDfs(int u, int p) {
    tin[u] = ++timer;
    up[u][0] = p;
    for (int i = 1; i <= lg; i++)
        up[u][i] = up[up[u][i - 1]][i - 1];
    for (ii e : adj[u]) {
        int v = e.first, w = e.second;
        if (v == p) continue;
        edgeWeight[v] = w;
        f[v] = f[u] + w;
        preDfs(v, u);
    };
    tout[u] = timer;
};
bool isAncestor(int u, int v) {
    return tin[u] <= tin[v] && tout[u] >= tout[v];
};
int __lca(int u, int v) {
    if (isAncestor(u, v)) return u;
    if (isAncestor(v, u)) return v;
    for (int i = lg; i >= 0; i--)
        if (!isAncestor(up[u][i], v))
            u = up[u][i];
    return up[u][0];
};
ll dist(int u, int v) {
    return f[u] + f[v] - f[__lca(u, v)] * 2;
};
void calcSize(int u, int p) {
    sz[u] = 1;
    for (ii e : adj[u]) {
        int v = e.first;
        if (v == p || del[v]) continue;
        calcSize(v, u);
        sz[u] += sz[v];
    };
};
int findCentroid(int u, int p, int n) {
    for (ii e : adj[u]) {
        int v = e.first;
        if (v == p || del[v]) continue;
        if (sz[v] * 2 > n) return findCentroid(v, u, n);
    };
    return u;
};
void collectNode(int root, int u, int p) {
    centNode[root].push_back(u);
    for (ii e : adj[u]) {
        int v = e.first;
        if (v == p || del[v]) continue;
        collectNode(root, v, u);
    };
};
void decompose(int u, int p) {
    calcSize(u, u);
    int centroid = findCentroid(u, u, sz[u]);
    par[centroid] = p;
    del[centroid] = true;
    collectNode(centroid, centroid, centroid);
    sort(all(centNode[centroid]), [&](int u, int v) {
        return tin[u] < tin[v];
    });
    for (ii e : adj[centroid]) {
        int v = e.first;
        if (del[v]) continue;
        decompose(v, centroid);
    };
};
ll sumPath(int u, int v) {
    return bit.get(tin[u]) + bit.get(tin[v]) - bit.get(tin[__lca(u, v)]) * 2;
};
ll query(int u) {
    ll res = INF;
    for (int v = u; v != 0; v = par[v]) {
        res = min(res, sumPath(u, v) + seg[v].getMin());
    };
    return res;
};
int findLeft(int x, const vector<int>& data) {
    int l = 0, r = (int)data.size() - 1, pos = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (tin[data[mid]] >= x) {
            pos = mid;
            r = mid - 1;
        } else
            l = mid + 1;
    };
    return pos;
};
int findRight(int x, const vector<int>& data) {
    int l = 0, r = (int)data.size() - 1, pos = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (tin[data[mid]] <= x) {
            pos = mid;
            l = mid + 1;
        } else
            r = mid - 1;
    };
    return pos;
};
void updateGrap(int u) {
    grap[u] ^= 1;
    for (int v = u; v != 0; v = par[v]) {
        int idx = findLeft(tin[u], centNode[v]) + 1;
        ll val = grap[u] ? sumPath(u, v) : INF;
        seg[v].assign(idx, val);
    };
};
void updateWeight(int u, int delta) {
    for (int v = par[u]; v != 0; v = par[v]) {
        int l = findLeft(tin[u], centNode[v]) + 1;
        if (l == 0) continue;
        int r = findRight(tout[u], centNode[v]) + 1;
        seg[v].update(l, r, delta);
    };
};
int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    if (fopen("MAIN.INP", "r")) {
        freopen("MAIN.INP", "r", stdin);
        freopen("MAIN.OUT", "w", stdout);
    };
    cin >> n >> q;
    for (int i = 1; i < n; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        adj[u].push_back(ii(v, w));
        adj[v].push_back(ii(u, w));
    };
    lg = ceil(log2(n));
    preDfs(1, 1);
    decompose(1, 0);
    int cntGrap = 0;
    for (int u = 1; u <= n; u++) {
        seg[u] = SegmentTree(centNode[u].size());
    };
    bit = FenwickTree(n);
    for (int u = 2; u <= n; u++) {
        bit.update(tin[u], edgeWeight[u]);
        bit.update(tout[u] + 1, -edgeWeight[u]);
    };
    while (q--) {
        int type, u;
        cin >> type >> u;
        if (type == 1) {
            cout << (cntGrap == 0 ? -1 : query(u)) << '\n';
        };
        if (type == 2) {
            cntGrap += (grap[u] ? -1 : 1);
            updateGrap(u);
        };
        if (type == 3) {
            int v, newWeight;
            cin >> v >> newWeight;
            if (isAncestor(v, u)) swap(u, v);
            int delta = -edgeWeight[v] + newWeight;
            bit.update(tin[v], delta);
            bit.update(tout[v] + 1, -delta);
            updateWeight(v, delta);
            edgeWeight[v] = newWeight;
        };
    };
};
Compilation message (stderr)
Main.cpp: In function 'int main()':
Main.cpp:262:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  262 |         freopen("MAIN.INP", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Main.cpp:263:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  263 |         freopen("MAIN.OUT", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |