#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>
#include <cassert>

const int N = 120005;
const int C = 1000000;

inline int read_int()
{
    int x = 0;
    char c;
    do {
        c = getchar_unlocked();
    } while (c < '0');
    do {
        x = (x << 1) + (x << 3) + (c - '0');
        c = getchar_unlocked();
    } while (c >= '0');
    return x;
}

struct EdgeInterval
{
    int edge;
    int s, e;
    
    EdgeInterval() = default;
    EdgeInterval(const int _edge, const int _s, const int _e) : edge(_edge), s(_s), e(_e) {
    }
};

std::vector<EdgeInterval> intvs[C];
std::vector<std::pair<int, int>> edge_queries[C]; // (time, edge)
std::tuple<int, int, int> queries[N];
std::pair<int, int> tree_edge[N - 1];
std::pair<int, int> last_update[N - 1]; // (time, color)

long long query_answers[C];
std::vector<int> color_updates[N + 1];
long long sum_tree[2 * C];
int idx[C];

// for solve_color
std::vector<int> tree[4 * 4 * N];
std::vector<std::pair<int, int>> normalized_queries[4 * N];

std::vector<int> deltas[C];
long long *fvalue_at[C];

long long f(int x) 
{
    return static_cast<long long>(x) * (x - 1) / 2;
}

struct DisjointSets
{
    int parent[N];
    int weight[N];
    std::vector<std::pair<int, int>> stk;
    
    long long fvalue;
    
    DisjointSets()
    {
        for (int i = 0; i < N; ++ i) {
            parent[i] = i;
            weight[i] = 1;
        }
        fvalue = 0;
    }
    
    int find_root(int x) const {
        return (parent[x] == x) ? x : find_root(parent[x]);    
    }
    
    void unite(int x, int y) 
    {
        x = find_root(x);
        y = find_root(y);
        if (x == y) {
            return;
        }
        
        if (y > x) {
            std::swap(x, y);
        }
        stk.emplace_back(x, y);
        fvalue -= f(weight[x]);
        fvalue -= f(weight[y]);
        
        weight[x] += weight[y];
        parent[y] = x;
        fvalue += f(weight[x]);
    }
    
    int get_size(int node) const
    {
        return weight[find_root(node)];   
    }
    
    int get_snapshot_idx() const 
    {
        return static_cast<int>(stk.size());
    }
    
    void undo_at(const int snapshot) 
    {
        while (static_cast<int>(stk.size()) > snapshot) {
            int x, y;
            x = stk.back().first;
            y = stk.back().second;
            
            fvalue -= f(weight[x]);
            parent[y] = y;
            weight[x] -= weight[y];
            fvalue += f(weight[x]);
            fvalue += f(weight[y]);
            
            stk.pop_back();
        }
    }
} DS;

void update_tree(int node, int l, int r, int ql, int qr, int edgeidx)
{
    if (ql <= l && r <= qr) {
        tree[node].push_back(edgeidx);
    } else {
        int mid = (l + r) >> 1;
        if (ql <= mid) {
            update_tree(2 * node + 1, l, mid, ql, qr, edgeidx);
        }
        if (mid < qr) {
            update_tree(2 * node + 2, mid + 1, r, ql, qr, edgeidx);
        }
    }
}

void dfs(const int color, int node, int l, int r) 
{
    const int snapshot = DS.get_snapshot_idx();
    for (auto&& edgeidx : tree[node]) {
        DS.unite(tree_edge[edgeidx].first, tree_edge[edgeidx].second);
    }
    tree[node].clear();
    
    if (l == r) {
        fvalue_at[color][l] = DS.fvalue;
        for (auto&& edge_query : normalized_queries[l]) {
            query_answers[edge_query.first] = f(DS.get_size(tree_edge[edge_query.second].first));
        }
        normalized_queries[l].clear();
    } else {
        int mid = (l + r) >> 1;
        dfs(color, 2 * node + 1, l, mid);
        dfs(color, 2 * node + 2, mid + 1, r);
    }
    
    DS.undo_at(snapshot);
}

void solve_color(int color)
{
    for (auto&& x : intvs[color]) {
        deltas[color].push_back(x.s);
        deltas[color].push_back(x.e);
        deltas[color].push_back(x.e + 1);
    }
    for (auto&& x : edge_queries[color]) {
        deltas[color].push_back(x.first);
    }
    std::sort(deltas[color].begin(), deltas[color].end());
    deltas[color].erase(std::unique(deltas[color].begin(), deltas[color].end()), deltas[color].end());
    
    int n = static_cast<int>(deltas[color].size());
    fvalue_at[color] = new long long[n];
    for (auto&& x : intvs[color]) {
        int a = std::lower_bound(deltas[color].begin(), deltas[color].end(), x.s) - deltas[color].begin();
        int b = std::lower_bound(deltas[color].begin(), deltas[color].end(), x.e) - deltas[color].begin();
        update_tree(0, 0, n - 1, a, b, x.edge);
    }
    for (auto&& x : edge_queries[color]) {
        normalized_queries[std::lower_bound(deltas[color].begin(), deltas[color].end(), x.first) - deltas[color].begin()].push_back(x);
    }
    
    dfs(color, 0, 0, n - 1);
}

int main()
{
    int n = read_int();
    for (int i = 0; i < n - 1; ++ i) {
        int x = read_int() - 1, y = read_int() - 1, color = read_int() - 1;
        tree_edge[i] = std::make_pair(x, y);
        last_update[i] = std::make_pair(-1, color);
    }
    
    int q = read_int();
    for (int i = 0; i < q; ++ i) {
        int qtype = read_int();
        if (qtype == 1) {
            int edgeidx = read_int() - 1, color = read_int() - 1;
            if (last_update[edgeidx].second != color) {
                intvs[last_update[edgeidx].second].emplace_back(edgeidx, last_update[edgeidx].first, i - 1);
                last_update[edgeidx] = std::make_pair(i, color);
            }
            queries[i] = std::make_tuple(-1, 0, 0);
        } else {
            if (qtype == 2) {
                int x = read_int() - 1, y = read_int() - 1;
                queries[i] = std::make_tuple(0, x, y);
            } else {
                int edgeidx = read_int() - 1;
                queries[i] = std::make_tuple(1, edgeidx, -1);
                edge_queries[last_update[edgeidx].second].emplace_back(i, edgeidx);   
            }
        }
    }
    
    for (int i = 0; i < n - 1; ++ i) {
        intvs[last_update[i].second].emplace_back(i, last_update[i].first, q);
    }
    for (int i = 0; i < q; ++ i) {
        query_answers[i] = -1;
    }
    for (int i = 0; i < C; ++ i) {
        if (!intvs[i].empty()) {
            //deltas[i].push_back(q);
            solve_color(i);
            for (auto&& x : deltas[i]) {
                if (x != -1) {
                    color_updates[x].push_back(i);
                } else {
                    sum_tree[i + C] = fvalue_at[i][0];
                    idx[i] = 1;
                }
            }
        }
    }
    
    for (int i = C - 1; i > 0; -- i) {
        sum_tree[i] = sum_tree[i << 1] + sum_tree[i << 1 | 1];
    }
    
    for (int i = 0; i < q; ++ i) {
        for (auto&& color : color_updates[i]) {
            sum_tree[color + C] = fvalue_at[color][idx[color]];
            for (int node = color + C; node > 0; node >>= 1) {
                sum_tree[node >> 1] = sum_tree[node ^ 1] + sum_tree[node];
            }
            
            idx[color]++;
        }
        
        if (std::get<0>(queries[i]) == 0) {
            query_answers[i] = 0ULL;
            for (int l = C + std::get<1>(queries[i]), r = 1 + C + std::get<2>(queries[i]); l < r; l >>= 1, r >>= 1) {
                if (l & 1) {
                    query_answers[i] += sum_tree[l++];
                }
                if (r & 1) {
                    query_answers[i] += sum_tree[--r];
                }
            }
        }
    }
    
    for (int i = 0; i < q; ++ i) {
        if (query_answers[i] != -1) {
            printf("%lld\n", query_answers[i]);
        }
    }
}