#pragma GCC optimize("O3,unroll-loops")
// Khuyên dùng avx2 thay vì avx512 vì nhiều judge (Codeforces, VNOI) không hỗ trợ tập lệnh avx512, dễ gây RE/WA.
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#include <bits/stdc++.h>
using namespace std;
// ===================== ROBUST FAST IO =====================
namespace FastIO {
const int BUF_SIZE = 1 << 16;
char buf[BUF_SIZE];
int buf_pos = BUF_SIZE, buf_len = BUF_SIZE;
inline char read_char() {
if (buf_pos == buf_len) {
buf_pos = 0;
buf_len = fread(buf, 1, BUF_SIZE, stdin);
if (buf_pos == buf_len) return EOF;
}
return buf[buf_pos++];
}
inline bool read_int(int &x) {
char c = read_char();
while (c != EOF && c <= 32) c = read_char();
if (c == EOF) return false;
int sig = 1;
if (c == '-') { sig = -1; c = read_char(); }
x = 0;
while (c > 32) { x = x * 10 + (c - '0'); c = read_char(); }
x *= sig;
return true;
}
inline bool read_ll(long long &x) {
char c = read_char();
while (c != EOF && c <= 32) c = read_char();
if (c == EOF) return false;
int sig = 1;
if (c == '-') { sig = -1; c = read_char(); }
x = 0;
while (c > 32) { x = x * 10 + (c - '0'); c = read_char(); }
x *= sig;
return true;
}
char out_buf[BUF_SIZE];
int out_pos = 0;
inline void write_char(char c) {
if (out_pos == BUF_SIZE) {
fwrite(out_buf, 1, out_pos, stdout);
out_pos = 0;
}
out_buf[out_pos++] = c;
}
inline void write_ll(long long x) {
if (x == 0) { write_char('0'); return; }
unsigned long long ux = x;
if (x < 0) { write_char('-'); ux = -x; }
char s[24]; int idx = 0;
while (ux > 0) { s[idx++] = (ux % 10) + '0'; ux /= 10; }
while (idx > 0) write_char(s[--idx]);
}
inline void flush() {
if (out_pos > 0) {
fwrite(out_buf, 1, out_pos, stdout);
out_pos = 0;
}
}
}
// ===================== SQRT DECOMP RARS CHUẨN =====================
// Tách biệt việc cộng sum_block ra khỏi vòng lặp để trình biên dịch có thể bung SIMD Parallel Packing
struct SqrtRARS {
static const int BLOCK = 256;
alignas(64) long long p[100005];
alignas(64) long long lazy[100005 / BLOCK + 5];
alignas(64) long long sum_block[100005 / BLOCK + 5];
inline void add(int l, int r, long long val) {
if (l > r) return;
int bl = l / BLOCK, br = r / BLOCK;
if (bl == br) {
sum_block[bl] += val * (r - l + 1);
#pragma GCC ivdep
for (int i = l; i <= r; ++i) p[i] += val;
} else {
sum_block[bl] += val * ((bl + 1) * BLOCK - l);
#pragma GCC ivdep
for (int i = l; i < (bl + 1) * BLOCK; ++i) p[i] += val;
for (int b = bl + 1; b < br; ++b) {
lazy[b] += val;
sum_block[b] += val * BLOCK;
}
sum_block[br] += val * (r - br * BLOCK + 1);
#pragma GCC ivdep
for (int i = br * BLOCK; i <= r; ++i) p[i] += val;
}
}
inline long long query(int l, int r) {
if (l > r) return 0;
long long res = 0;
int bl = l / BLOCK, br = r / BLOCK;
if (bl == br) {
res += lazy[bl] * (r - l + 1);
long long temp = 0;
#pragma GCC ivdep
for (int i = l; i <= r; ++i) temp += p[i];
res += temp;
} else {
res += lazy[bl] * ((bl + 1) * BLOCK - l);
long long temp_l = 0;
#pragma GCC ivdep
for (int i = l; i < (bl + 1) * BLOCK; ++i) temp_l += p[i];
res += temp_l;
for (int b = bl + 1; b < br; ++b) res += sum_block[b];
res += lazy[br] * (r - br * BLOCK + 1);
long long temp_r = 0;
#pragma GCC ivdep
for (int i = br * BLOCK; i <= r; ++i) temp_r += p[i];
res += temp_r;
}
return res;
}
};
// ===================== MAIN OFFLINE TREE LOGIC =====================
const int MOD = 1e9 + 7;
const int B = 700; // Giữ nguyên B=700 cho thuật toán block query trên cây, không giảm xuống 256.
struct Edge { int v, id; };
struct QueryInfo { int u, c, id; };
struct Event { int type; int u; int c; long long v; int id; };
int N, Q;
alignas(64) int global_C[100005];
alignas(64) long long global_V[100005];
alignas(64) long long global_W[100005];
alignas(64) int edge_u[100005], edge_v[100005];
vector<Edge> spatial_adj[100005];
alignas(64) int v_type[100005];
alignas(64) int v_u[100005], v_c[100005];
alignas(64) long long v_v[100005];
alignas(64) int v_edge[100005];
alignas(64) long long v_w[100005];
vector<int> v_adj[100005];
vector<QueryInfo> q_list[100005];
alignas(64) int old_c[100005];
alignas(64) long long old_v[100005];
alignas(64) long long old_w[100005];
vector<Event> E;
alignas(64) long long query_answers[100005];
int query_count = 0;
int tin[100005], tout[100005], timer = 0;
int euler[200005], euler_depth[200005], first_occ[100005], euler_timer = 0;
int st_lca[18][200005];
int parent_orig[100005], edge_id_orig[100005];
void dfs_lca(int u, int p, int d) {
tin[u] = ++timer;
euler[++euler_timer] = u;
euler_depth[euler_timer] = d;
first_occ[u] = euler_timer;
parent_orig[u] = p;
for (auto& edge : spatial_adj[u]) {
int v = edge.v;
if (v != p) {
edge_id_orig[v] = edge.id;
dfs_lca(v, u, d + 1);
euler[++euler_timer] = u;
euler_depth[euler_timer] = d;
}
}
tout[u] = timer;
}
void build_rmq() {
for (int i = 1; i <= euler_timer; ++i) st_lca[0][i] = i;
for (int j = 1; (1 << j) <= euler_timer; ++j) {
for (int i = 1; i + (1 << j) - 1 <= euler_timer; ++i) {
int a = st_lca[j-1][i];
int b = st_lca[j-1][i + (1 << (j-1))];
st_lca[j][i] = (euler_depth[a] < euler_depth[b]) ? a : b;
}
}
}
int get_lca(int u, int v) {
int L = first_occ[u], R = first_occ[v];
if (L > R) swap(L, R);
int j = __lg(R - L + 1);
int a = st_lca[j][L];
int b = st_lca[j][R - (1 << j) + 1];
return euler[(euler_depth[a] < euler_depth[b]) ? a : b];
}
void prep_dfs(int v) {
if (v != 0) {
if (v_type[v] == 1) {
old_c[v] = global_C[v_u[v]]; old_v[v] = global_V[v_u[v]];
global_C[v_u[v]] = v_c[v]; global_V[v_u[v]] = v_v[v];
} else {
old_w[v] = global_W[v_edge[v]];
global_W[v_edge[v]] = v_w[v];
}
}
for (int nxt : v_adj[v]) prep_dfs(nxt);
if (v != 0) {
if (v_type[v] == 1) {
global_C[v_u[v]] = old_c[v]; global_V[v_u[v]] = old_v[v];
} else {
global_W[v_edge[v]] = old_w[v];
}
}
}
void build_E(int v) {
for (auto& q : q_list[v]) E.push_back({3, q.u, q.c, 0, q.id});
for (int nxt : v_adj[v]) {
if (v_type[nxt] == 1) E.push_back({1, v_u[nxt], v_c[nxt], v_v[nxt], 0});
else E.push_back({2, v_edge[nxt], 0, v_w[nxt], 0});
build_E(nxt);
if (v_type[nxt] == 1) E.push_back({1, v_u[nxt], old_c[nxt], old_v[nxt], 0});
else E.push_back({2, v_edge[nxt], 0, old_w[nxt], 0});
}
}
alignas(64) int color_map[100005];
bool in_VQ[100005];
bool is_changing[100005];
alignas(64) int vq_idx[100005];
alignas(64) int vq_parent[100005];
alignas(64) long long D_stat[100005];
alignas(64) long long D_true[100005];
alignas(64) int p_x[100005];
alignas(64) int C_curr[100005];
alignas(64) long long V_curr[100005];
alignas(64) long long W_curr[100005];
alignas(64) int SumV[15000][750];
alignas(64) int SumVD[15000][750];
vector<int> active_p[750];
void dfs_spatial(int u, int p, long long d, int anc) {
if (in_VQ[u]) anc = u;
p_x[u] = anc;
D_stat[u] = d;
for (auto& edge : spatial_adj[u]) {
int v = edge.v;
if (v != p) dfs_spatial(v, u, (d + global_W[edge.id]) % MOD, anc);
}
}
int main() {
if (!FastIO::read_int(N) || !FastIO::read_int(Q)) return 0;
for (int i = 1; i <= N; ++i) FastIO::read_int(global_C[i]);
for (int i = 1; i <= N; ++i) FastIO::read_ll(global_V[i]);
for (int i = 1; i < N; ++i) {
FastIO::read_int(edge_u[i]);
FastIO::read_int(edge_v[i]);
FastIO::read_ll(global_W[i]);
spatial_adj[edge_u[i]].push_back({edge_v[i], i});
spatial_adj[edge_v[i]].push_back({edge_u[i], i});
}
dfs_lca(1, 0, 0);
build_rmq();
int version_nodes = 0;
int current_version = 0;
vector<int> version_at_query(Q + 1, 0);
for (int i = 1; i <= Q; ++i) {
int type; FastIO::read_int(type);
if (type == 1) {
int u, c; long long v;
FastIO::read_int(u); FastIO::read_int(c); FastIO::read_ll(v);
v_adj[current_version].push_back(++version_nodes);
v_type[version_nodes] = 1;
v_u[version_nodes] = u; v_c[version_nodes] = c; v_v[version_nodes] = v;
current_version = version_nodes;
} else if (type == 2) {
int edge_id; long long w;
FastIO::read_int(edge_id); FastIO::read_ll(w);
v_adj[current_version].push_back(++version_nodes);
v_type[version_nodes] = 2;
v_edge[version_nodes] = edge_id; v_w[version_nodes] = w;
current_version = version_nodes;
} else if (type == 3) {
int u, c;
FastIO::read_int(u); FastIO::read_int(c);
q_list[current_version].push_back({u, c, ++query_count});
} else if (type == 4) {
int k; FastIO::read_int(k);
current_version = version_at_query[k];
}
version_at_query[i] = current_version;
}
prep_dfs(0);
build_E(0);
memset(color_map, -1, sizeof(color_map));
int M = E.size();
for (int L = 0; L < M; L += B) {
int R = min(M - 1, L + B - 1);
vector<int> I = {1};
vector<int> E_change;
for (int i = L; i <= R; ++i) {
if (E[i].type == 1 || E[i].type == 3) I.push_back(E[i].u);
else if (E[i].type == 2) {
I.push_back(edge_u[E[i].u]);
I.push_back(edge_v[E[i].u]);
E_change.push_back(E[i].u);
}
}
sort(I.begin(), I.end(), [](int a, int b) { return tin[a] < tin[b]; });
I.erase(unique(I.begin(), I.end()), I.end());
int k_I = I.size();
for (int i = 0; i < k_I - 1; ++i) I.push_back(get_lca(I[i], I[i+1]));
sort(I.begin(), I.end(), [](int a, int b) { return tin[a] < tin[b]; });
I.erase(unique(I.begin(), I.end()), I.end());
vector<int> st;
for (int i = 0; i < I.size(); ++i) {
int u = I[i];
vq_idx[u] = i;
in_VQ[u] = true;
while (!st.empty() && tout[st.back()] < tin[u]) st.pop_back();
vq_parent[u] = st.empty() ? 0 : st.back();
st.push_back(u);
}
sort(E_change.begin(), E_change.end());
E_change.erase(unique(E_change.begin(), E_change.end()), E_change.end());
for (int e : E_change) is_changing[e] = true;
dfs_spatial(1, 0, 0, 1);
vector<int> Q_C;
for (int i = L; i <= R; ++i) {
if (E[i].type == 3) {
if (color_map[E[i].c] == -1) {
color_map[E[i].c] = Q_C.size();
Q_C.push_back(E[i].c);
}
}
}
int num_c = Q_C.size();
for (int i = 0; i < I.size(); ++i) {
for (int j = 0; j < num_c; ++j) SumV[i][j] = SumVD[i][j] = 0;
}
for (int j = 0; j < num_c; ++j) active_p[j].clear();
for (int u = 1; u <= N; ++u) {
if (!in_VQ[u]) {
int c_map = color_map[global_C[u]];
if (c_map != -1) {
int p = p_x[u];
int p_idx = vq_idx[p];
SumV[p_idx][c_map] = (SumV[p_idx][c_map] + global_V[u]) % MOD;
long long d_px = (D_stat[u] - D_stat[p] + MOD) % MOD;
// FIX: Modulo global_V trước khi nhân để tránh tràn giới hạn long long
SumVD[p_idx][c_map] = (SumVD[p_idx][c_map] + (global_V[u] % MOD) * d_px) % MOD;
}
}
}
for (int i = 0; i < I.size(); ++i) {
for (int j = 0; j < num_c; ++j) {
if (SumV[i][j] > 0 || SumVD[i][j] > 0) active_p[j].push_back(I[i]);
}
}
for (int u : I) { C_curr[u] = global_C[u]; V_curr[u] = global_V[u]; }
for (int e : E_change) W_curr[e] = global_W[e];
for (int i = L; i <= R; ++i) {
if (E[i].type == 1) {
C_curr[E[i].u] = E[i].c; V_curr[E[i].u] = E[i].v;
} else if (E[i].type == 2) {
W_curr[E[i].u] = E[i].v;
} else if (E[i].type == 3) {
for (int u : I) {
if (vq_parent[u] == 0) D_true[u] = 0;
else {
int p = vq_parent[u];
long long len = 0;
if (parent_orig[u] == p && is_changing[edge_id_orig[u]]) {
len = W_curr[edge_id_orig[u]];
} else {
len = (D_stat[u] - D_stat[p] + MOD) % MOD;
}
D_true[u] = (D_true[p] + len) % MOD;
}
}
long long ans = 0;
int q_u = E[i].u; int q_c = E[i].c;
for (int x : I) {
if (C_curr[x] == q_c) {
int lca_ux = get_lca(q_u, x);
long long dist = (D_true[q_u] + D_true[x] - 2 * D_true[lca_ux]) % MOD;
if (dist < 0) dist += MOD;
ans = (ans + (V_curr[x] % MOD) * dist) % MOD;
}
}
int c_map = color_map[q_c];
if (c_map != -1) {
for (int p : active_p[c_map]) {
int lca_up = get_lca(q_u, p);
long long dist = (D_true[q_u] + D_true[p] - 2 * D_true[lca_up]) % MOD;
if (dist < 0) dist += MOD;
int p_idx = vq_idx[p];
ans = (ans + 1LL * SumV[p_idx][c_map] * dist + SumVD[p_idx][c_map]) % MOD;
}
}
query_answers[E[i].id] = ans;
}
}
for (int i = L; i <= R; ++i) {
if (E[i].type == 1) {
global_C[E[i].u] = E[i].c; global_V[E[i].u] = E[i].v;
} else if (E[i].type == 2) {
global_W[E[i].u] = E[i].v;
}
}
for (int u : I) in_VQ[u] = false;
for (int e : E_change) is_changing[e] = false;
for (int c : Q_C) color_map[c] = -1;
}
for (int i = 1; i <= query_count; ++i) {
FastIO::write_ll(query_answers[i]);
FastIO::write_char('\n');
}
FastIO::flush();
return 0;
}