#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int BLOCK_SIZE = 1000;
struct Edge {
int u, v, d, id;
};
struct Query {
int type, x, y, id;
};
struct RollbackDSU {
vector<int> parent, sz;
vector<pair<int, int>> history;
RollbackDSU(int n) {
parent.resize(n + 1);
sz.resize(n + 1, 1);
for (int i = 1; i <= n; i++) parent[i] = i;
}
int find(int i) {
if (parent[i] == i) return i;
return find(parent[i]);
}
bool merge(int u, int v) {
int root_u = find(u);
int root_v = find(v);
if (root_u == root_v) return false;
if (sz[root_u] < sz[root_v]) swap(root_u, root_v);
parent[root_v] = root_u;
sz[root_u] += sz[root_v];
history.push_back({root_v, root_u}); // ??????????? ????????
return true;
}
void rollback(int steps) {
while (steps > 0 && !history.empty()) {
int v = history.back().first;
int u = history.back().second;
history.pop_back();
sz[u] -= sz[v];
parent[v] = v;
steps--;
}
}
int get_size(int u) {
return sz[find(u)];
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
if (!(cin >> n >> m)) return 0;
vector<Edge> edges(m + 1);
vector<int> current_weight(m + 1);
for (int i = 1; i <= m; i++) {
cin >> edges[i].u >> edges[i].v >> edges[i].d;
edges[i].id = i;
current_weight[i] = edges[i].d;
}
int q;
cin >> q;
vector<Query> queries(q);
for (int i = 0; i < q; i++) {
cin >> queries[i].type >> queries[i].x >> queries[i].y;
queries[i].id = i;
}
vector<int> ans(q, -1);
vector<bool> changed(m + 1, false);
for (int l = 0; l < q; l += BLOCK_SIZE) {
int r = min(q - 1, l + BLOCK_SIZE - 1);
vector<Query> ask_queries;
vector<int> to_change; // ??? ???? ????? ?????????? ??????????? ID
for (int i = l; i <= r; i++) {
if (queries[i].type == 1) {
changed[queries[i].x] = true;
to_change.push_back(queries[i].x);
} else {
ask_queries.push_back(queries[i]);
}
}
vector<Edge> unchanged_edges;
for (int i = 1; i <= m; i++) {
if (!changed[i]) {
unchanged_edges.push_back({edges[i].u, edges[i].v, current_weight[i], i});
}
}
sort(unchanged_edges.begin(), unchanged_edges.end(), [](const Edge& a, const Edge& b) {
return a.d > b.d;
});
sort(ask_queries.begin(), ask_queries.end(), [](const Query& a, const Query& b) {
return a.y > b.y;
});
RollbackDSU dsu(n);
int edge_ptr = 0;
for (auto& qry : ask_queries) {
while (edge_ptr < unchanged_edges.size() && unchanged_edges[edge_ptr].d >= qry.y) {
dsu.merge(unchanged_edges[edge_ptr].u, unchanged_edges[edge_ptr].v);
edge_ptr++;
}
int rollback_steps = 0;
vector<int> temp_weights; // ??????????? ??????????? ??????? ??????? ???? ????
for (int id : to_change) {
changed[id] = false; // ??? ??????? ?????????
}
for (int i = l; i <= qry.id; i++) {
if (queries[i].type == 1) {
current_weight[queries[i].x] = queries[i].y;
}
}
for (int id : to_change) {
if (!changed[id]) { // ???? ????? ???? ????? ??????????? ???? ????? ??? 1 ? ???? ????
changed[id] = true;
if (current_weight[id] >= qry.y) {
if (dsu.merge(edges[id].u, edges[id].v)) {
rollback_steps++;
}
}
}
}
ans[qry.id] = dsu.get_size(qry.x);
dsu.rollback(rollback_steps);
for (int i = l; i <= qry.id; i++) {
if (queries[i].type == 1) {
}
}
}
for (int id : to_change) changed[id] = false;
for (int i = l; i <= r; i++) {
if (queries[i].type == 1) {
current_weight[queries[i].x] = queries[i].y;
}
}
}
for (int i = 0; i < q; i++) {
if (ans[i] != -1) cout << ans[i] << "\n";
}
return 0;
}