#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
struct Fenwick {
int n;
vector<ll> f;
Fenwick(int n=0){ init(n); }
void init(int n_){ n = (int)n_; f.assign(n+5, 0); }
void add(int i, ll delta){
for(; i <= n; i += i & -i) f[i] += delta;
}
void range_add(int l, int r, ll val){
if(l > r) return;
add((int)l, val);
add((int)r + 1, -val);
}
ll point_query(int i){
ll res = 0;
for(; i > 0; i -= i & -i) res += f[i];
return res;
}
};
const int MAXN = 200000 + 5;
const int LOG = 20;
int N, M, Q;
vector<vector<int>> g;
int up[MAXN][LOG];
int depthArr[MAXN];
void dfs_set_parent(int root){
// iterative DFS to avoid recursion depth issues optionally
vector<int> st;
st.reserve(N);
st.push_back(root);
up[root][0] = root;
depthArr[root] = 0;
vector<int> parent(N+1, -1);
parent[root] = root;
while(!st.empty()){
int u = st.back(); st.pop_back();
for(int v: g[u]){
if(parent[v] == -1){
parent[v] = u;
up[v][0] = u;
depthArr[v] = depthArr[u] + 1;
st.push_back(v);
}
}
}
}
int lca(int a, int b){
if(a == 0 || b == 0) return a ^ b; // defensive
if(depthArr[a] < depthArr[b]) swap(a,b);
int k = depthArr[a] - depthArr[b];
for(int j = 0; j < LOG; ++j) if(k & (1<<j)) a = up[a][j];
if(a == b) return a;
for(int j = LOG-1; j >= 0; --j){
if(up[a][j] != up[b][j]){
a = up[a][j];
b = up[b][j];
}
}
return up[a][0];
}
int distNode(int a, int b){
int w = lca(a,b);
return depthArr[a] + depthArr[b] - 2 * depthArr[w];
}
// interval map
struct Interval {
int l, r;
int pos;
};
map<int, Interval> mp; // key = l (start index)
vector< set<int> > byPos; // byPos[node] stores starting indices l of intervals with pos=node
Fenwick bit;
auto splitInterval(int x){
if(mp.empty()) return mp.end();
auto it = mp.lower_bound((int)x);
if(it != mp.end() && it->first == x) return it;
it = mp.upper_bound((int)x);
if(it == mp.begin()) return mp.end();
--it;
Interval cur = it->second;
if(cur.r < x) return mp.end();
// split [l, r] -> [l, x-1] and [x, r]
int l = cur.l, r = cur.r, p = cur.pos;
it->second.r = (int)(x - 1);
mp[(int)x] = {(int)x, r, p};
byPos[(size_t)p].insert((int)x);
return mp.find((int)x);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
freopen("HSSV.inp", "r", stdin);
freopen("HSSV.out", "w", stdout);
if(!(cin >> N >> M >> Q)) return 0;
vector<int> a(M+2);
for(int i = 1; i <= M; ++i) cin >> a[i];
g.assign(N+1, {});
for(int i = 0; i < N-1; ++i){
int u,v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
// init up table to 0
for(int i=1;i<=N;i++) for(int j=0;j<LOG;j++) up[i][j] = 0;
// build parents & depth (iterative DFS)
dfs_set_parent(1);
// build binary lifting table
for(int j=1;j<LOG;j++){
for(int i=1;i<=N;i++){
int mid = up[i][j-1];
up[i][j] = up[mid][j-1];
if(up[i][j] == 0) up[i][j] = up[mid][j-1]; // defensive
}
}
// Fenwick init on M employees
bit.init((int)M);
byPos.assign(N+1, set<int>());
// build initial intervals from array a[1..M], merging adjacent same pos
int curL = 1;
for(int i = 2; i <= M+1; ++i){
if(i == M+1 || a[i] != a[i-1]){
int l = curL, r = i-1, p = a[l];
mp[l] = {l, r, p};
byPos[(size_t)p].insert(l);
curL = i;
}
}
while(Q--){
int type; cin >> type;
if(type == 1){
int u, v; cin >> u >> v;
if(u < 1 || u > N) continue;
if(byPos[(size_t)u].empty()) continue;
vector<int> starts;
starts.reserve(byPos[(size_t)u].size());
for(int s : byPos[(size_t)u]) starts.push_back(s);
for(int s : starts){
auto it = mp.find(s);
if(it == mp.end()) continue;
Interval iv = it->second;
if(iv.pos != u) continue;
bit.range_add(iv.l, iv.r, (ll)v);
}
} else if(type == 2){
int L, R, z; cin >> L >> R >> z;
if(L > R) swap(L, R);
if(L < 1) L = 1;
if(R > M) R = M;
if(L > R) continue;
// split at L and R+1
splitInterval((int)L);
splitInterval((int)R + 1);
auto itL = mp.lower_bound((int)L);
if(itL == mp.end() || itL->first > R){
// there was no existing intervals inside [L,R], simply insert [L,R] at pos z
mp[(int)L] = {(int)L, (int)R, z};
byPos[(size_t)z].insert((int)L);
} else {
// collect intervals in [L,R]
vector<int> toRemoveStarts;
vector<Interval> movedIntervals;
auto it = itL;
while(it != mp.end() && it->first <= R){
movedIntervals.push_back(it->second);
toRemoveStarts.push_back(it->first);
++it;
}
for(const Interval &iv : movedIntervals){
int l = iv.l, r = iv.r, p = iv.pos;
int d = distNode(p, z);
if(d != 0) bit.range_add(l, r, - (ll)d);
auto itset = byPos[(size_t)p].find(l);
if(itset != byPos[(size_t)p].end()) byPos[(size_t)p].erase(itset);
}
for(int s : toRemoveStarts) mp.erase(s);
// insert new interval [L,R] with pos=z
mp[(int)L] = {(int)L, (int)R, z};
byPos[(size_t)z].insert((int)L);
}
// merge with previous and next safely: capture keys before erasing
auto itNew = mp.find((int)L);
if(itNew != mp.begin()){
auto itPrev = itNew; --itPrev;
if(itPrev->second.pos == itNew->second.pos && itPrev->second.r + 1 == itNew->second.l){
int nl = itPrev->second.l;
int nr = itNew->second.r;
int p = itNew->second.pos;
// erase keys safely
byPos[(size_t)p].erase(itPrev->second.l);
byPos[(size_t)p].erase(itNew->second.l);
mp.erase(itPrev);
mp.erase(itNew);
mp[nl] = {nl, nr, p};
byPos[(size_t)p].insert(nl);
itNew = mp.find(nl);
}
}
// merge with next
auto itNext = itNew; ++itNext;
if(itNext != mp.end()){
if(itNext->second.pos == itNew->second.pos && itNew->second.r + 1 == itNext->second.l){
int nl = itNew->second.l;
int nr = itNext->second.r;
int p = itNew->second.pos;
byPos[(size_t)p].erase(itNew->second.l);
byPos[(size_t)p].erase(itNext->second.l);
mp.erase(itNew);
mp.erase(itNext);
mp[nl] = {nl, nr, p};
byPos[(size_t)p].insert(nl);
}
}
} else if(type == 3){
int i; cin >> i;
if(i < 1 || i > M) {
cout << 0 << '\n';
} else {
cout << bit.point_query((int)i) << '\n';
}
}
}
return 0;
}