#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1e6 + 5;
#define INF 0x3f3f3f3f
struct Segment_Tree {
int Left, Right, Max_Data, Sum_Data, Lazy_Tag;
#define LC(x) (x << 1)
#define RC(x) (x << 1 | 1)
#define L(x) tree[x].Left
#define R(x) tree[x].Right
#define T(x) tree[x].Lazy_Tag
#define A(x) tree[x].Max_Data
#define S(x) tree[x].Sum_Data
};
Segment_Tree tree[MAXN << 2];
struct Edge {
int Next, To;
};
Edge edge[MAXN << 1];
int head[MAXN];
int edgetot = 1;
int dfn[MAXN], dep[MAXN], siz[MAXN], son[MAXN], tp[MAXN], fa[MAXN];
int w[MAXN];
int n, q;
int tim;
void Addedge(int x, int y) {
edge[++edgetot].Next = head[x], edge[edgetot].To = y, head[x] = edgetot;
edge[++edgetot].Next = head[y], edge[edgetot].To = x, head[y] = edgetot;
}
void Push_Up(int pos) {
S(pos) = S(LC(pos)) + S(RC(pos));
A(pos) = max(A(LC(pos)), A(RC(pos)));
}
void Build(int pos, int l, int r) {
L(pos) = l;
R(pos) = r;
if(l == r)
return;
int mid = (l + r) >> 1;
Build(LC(pos), l, mid);
Build(RC(pos), mid + 1, r);
}
void Update(int pos, int x, int k) {
if(L(pos) == R(pos)) {
A(pos) = S(pos) = k;
return;
}
if(R(LC(pos)) >= x)
Update(LC(pos), x, k);
else
Update(RC(pos), x, k);
Push_Up(pos);
}
int Query_Max(int pos, int l, int r) {
if(l <= L(pos) && R(pos) <= r)
return A(pos);
int res = -INF;
if(R(LC(pos)) >= l)
res = max(res, Query_Max(LC(pos), l, r));
if(L(RC(pos)) <= r)
res = max(res, Query_Max(RC(pos), l, r));
return res;
}
int Max_Past(int x, int y) {
int res = -INF;
while(tp[x] != tp[y]) {
if(dep[tp[x]] < dep[tp[y]])
swap(x, y);
res = max(res, Query_Max(1, dfn[tp[x]], dfn[x]));
x = fa[tp[x]];
}
if(dep[x] > dep[y])
swap(x, y);
res = max(res, Query_Max(1, dfn[x], dfn[y]));
return res;
}
int Query_Sum(int pos, int l, int r) {
if(l <= L(pos) && R(pos) <= r)
return S(pos);
int res = 0;
if(R(LC(pos)) >= l)
res += Query_Sum(LC(pos), l, r);
if(L(RC(pos)) <= r)
res += Query_Sum(RC(pos), l, r);
return res;
}
int Sum_Past(int x, int y) {
int res = 0;
while(tp[x] != tp[y]) {
if(dep[tp[x]] < dep[tp[y]])
swap(x, y);
res += Query_Sum(1, dfn[tp[x]], dfn[x]);
x = fa[tp[x]];
}
if(dep[x] > dep[y])
swap(x, y);
res += Query_Sum(1, dfn[x], dfn[y]);
return res;
}
void dfs1(int u, int pre) {
dep[u] = dep[pre] + 1;
fa[u] = pre;
siz[u] = 1;
int maxn = -INF;
for(int i = head[u]; i; i = edge[i].Next) {
int v = edge[i].To;
if(v != pre) {
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > maxn) {
son[u] = v;
maxn = siz[v];
}
}
}
}
void dfs2(int u, int Top) {
dfn[u] = ++tim;
tp[u] = Top;
if(son[u])
dfs2(son[u], Top);
for(int i = head[u]; i; i = edge[i].Next) {
int v = edge[i].To;
if(v != son[u] && v != fa[u])
dfs2(v, v);
}
}
int main() {
scanf("%d", &n);
for(int i = 1, a, b; i < n; i++) {
scanf("%d %d", &a, &b);
Addedge(a, b);
}
dfs1(1, 0);
dfs2(1, 1);
Build(1, 1, tim);
for(int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
Update(1, dfn[i], w[i]);
}
char opt[10];
int u, v;
for(scanf("%d", &q); q; q--) {
scanf("%s", opt);
scanf("%d %d", &u, &v);
if(opt[0] == 'C')
Update(1, u, v);
else if(opt[1] == 'M')
printf("%d\n", Max_Past(u, v));
else
printf("%d\n", Sum_Past(u, v));
}
return 0;
}