#include<iostream>
#include<limits.h>
#define MAXN 200005
using namespace std;
int n,m,u,v,w;
struct EDGE {
int from,to,next,w;
} edge[MAXN<<1];
int cnt=0,head[MAXN];
inline void add_edge(int u,int v,int w) {
++cnt;
edge[cnt].w=w, edge[cnt].from=u, edge[cnt].to=v,edge[cnt].next=head[u];
head[u]=cnt;
}
int x,father[MAXN],depth[MAXN],siz[MAXN],val[MAXN], son[MAXN];
inline void dfs1(int x,int fa,int deep,const int& edge_num) {
depth[x]=deep, father[x]=fa, val[x]=edge[edge_num].w;
siz[x]=1;
int maxson=-1;
for(int i=head[x],v; i; i=edge[i].next) {
v=edge[i].to;
if(v==fa) continue;
dfs1(v,x,deep+1,i);
siz[x]+=siz[v];
if(siz[v]>maxson) son[x]=v,maxson=siz[v];
}
}
int id[MAXN],top[MAXN],va[MAXN],tot=0;
inline void dfs2(int x,int topf) {
id[x]=++tot;
va[tot]=val[x];
top[x]=topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i=head[x],v; i; i=edge[i].next) {
v=edge[i].to;
if(v==father[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int query_sum(int,int,int);
int query_max(int,int,int);
int query_min(int,int,int);
void changeSegment(int,int,int);
int query_two_point_sum(int x,int y) {
int ans=0;
while(top[x]!=top[y]) {
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ans+=query_sum(1,id[top[x]],id[x]);
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
ans+=query_sum(1,id[x],id[y]);
return ans;
}
int query_two_point_max(int x,int y) {
int ans=INT_MIN;
while(top[x]!=top[y]) {
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ans=max(ans,query_max(1,id[top[x]],id[x]));
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
ans=max(ans,query_max(1,id[x],id[y]));
return ans;
}
int query_two_point_min(int x,int y) {
int ans=INT_MAX;
while(top[x]!=top[y]) {
if(depth[top[x]]<depth[top[y]]) swap(x,y);
ans=min(ans,query_min(1,id[top[x]],id[x]));
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
ans=min(ans,query_min(1,id[x],id[y]));
return ans;
}
void change_two_point(int x,int y) {
while(top[x]!=top[y]) {
if(depth[top[x]]<depth[top[y]]) swap(x,y);
changeSegment(1,id[top[x]],id[x]);
x=father[top[x]];
}
if(depth[x]>depth[y]) swap(x,y);
changeSegment(1,id[x],id[y]);
}
struct NODE {
int l,r,sum,max_val,min_val,lazy;
} node[MAXN<<2];
inline void update(const int& x) {
node[x].max_val=max(node[x<<1].max_val,node[x<<1|1].max_val);
node[x].min_val=min(node[x<<1].min_val,node[x<<1|1].min_val);
node[x].sum=node[x<<1].sum+node[x<<1|1].sum;
}
void build_tree(int x,int l,int r) {
node[x].l=l, node[x].r=r;
if(l==r) {
node[x].sum=node[x].min_val=node[x].max_val=va[l];
node[x].lazy=0;
return;
}
int mid=l+r>>1;
build_tree(x<<1,l,mid);
build_tree(x<<1|1,mid+1,r);
update(x);
}
void pushdown(int x) {
if(node[x].l==node[x].r) {
lazy[x]=0;
return;
}
node[x].lazy=0;
node[x<<1].sum*=-1, node[x<<1|1].sum*=-1;
swap(node[x<<1].max_val, node[x<<1].min_val);
swap(node[x<<1|1].max_val, node[x<<1|1].min_val);
node[x<<1].max_val*=-1, node[x<<1].min_val*=-1;
node[x<<1|1].max_val*=-1, node[x<<1|1].min_val*=-1;
node[x<<1].lazy=(node[x<<1].lazy+1)%2, node[x<<1|1].lazy=(node[x<<1|1].lazy+1)%2;
}
void changeSegment(int x,int L,int R) {
if(node[x].l==L&&node[x].r==R) {
if(node[x].lazy) {
node[x].lazy=0;
returm;
}
node[x].sum*=-1;
swap(node[x].max_val, node[x].min_val);
node[x].max_val*=-1, node[x].min_val*=-1;
node[x].lazy=1;
return;
}
if(node[x].lazy) pushdown(x);
int mid=node[x].l+node[x].r>>1;
if(R<=mid) changeSegment(x<<1,L,R);
else if(L>mid) changeSegment(x<<1|1,L,R);
else changeSegment(x<<1,L,mid),changeSegment(x<<1|1,mid+1,R);
update(x);
}
void change_one_point(const int& x,const int& target,const int& val) {
if(node[x].l==node[x].r) {
node[x].min_val=node[x].max_val=node[x].sum=val;
return;
}
int mid=node[x].l+node[x].r>>1;
if(target<=mid) change_one_point(x<<1,target,val);
else change_one_point(x<<1|1,target,val);
update(x);
}
int query_sum(int x,int L,int R) {
if(node[x].l==L&&node[x].r==R) return node[x].sum;
if(node[x].lazy) pushdown(x);
int mid=node[x].l+node[x].r>>1;
if(R<=mid) return query_sum(x<<1,L,R);
else if(L>mid) return query_sum(x<<1|1,L,R);
else return query_sum(x<<1,L,mid) + query_sum(x<<1|1,mid+1,R);
}
int query_max(int x,int L,int R) {
if(node[x].l==L&&node[x].r==R) return node[x].max_val;
if(node[x].lazy) pushdown(x);
int mid=node[x].l+node[x].r>>1;
if(R<=mid) return query_max(x<<1,L,R);
else if(L>mid) return query_max(x<<1|1,L,R);
else return max( query_max(x<<1,L,mid), query_max(x<<1|1,mid+1,R) );
}
int query_min(int x,int L,int R) {
if(node[x].l==L&&node[x].r==R) return node[x].min_val;
if(node[x].lazy) pushdown(x);
int mid=node[x].l+node[x].r>>1;
if(R<=mid) return query_min(x<<1,L,R);
else if(L>mid) return query_min(x<<1|1,L,R);
else return min( query_min(x<<1,L,mid), query_min(x<<1|1,mid+1,R) );
}
int main() {freopen("D:\\stdin.txt","r",stdin);
freopen("D:\\stdout.txt","w",stdout);
cin>>n;
for(int i=1; i<n; i++) {
scanf("%d%d%d",&u,&v,&w);
++u,++v;
add_edge(u,v,w), add_edge(v,u,w);
}
edge[0].w=0;
dfs1(1,0,0,0);
dfs2(1,1);
build_tree(1,1,n);
int m;
string op_code;
cin>>m;
while(m--) {
cin>>op_code;
if(op_code=="C") {
scanf("%d%d",&u,&v);
int target=u*2;
if(depth[edge[target].from]>depth[edge[target].to]) target=edge[target].from;
else target=edge[target].to;
change_one_point(1,id[target],v);
} else if(op_code=="N") {
scanf("%d%d",&u,&v);
++u,++v;
change_two_point(u,v);
} else if(op_code=="SUM") {
scanf("%d%d",&u,&v);
++u,++v;
printf("%d\n",query_two_point_sum(u,v));
} else if(op_code=="MAX") {
scanf("%d%d",&u,&v);
++u,++v;
printf("%d\n",query_two_point_max(u,v));
} else if(op_code=="MIN") {
scanf("%d%d",&u,&v);
++u,++v;
printf("%d\n",query_two_point_min(u,v));
}
}
return 0;
}