#include<bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define cmax(a,b) if(a<b)a=b
#define cmin(a,b) if(a>b)a=b
using namespace std;
struct segment_tree{
struct node{
int lazy,maxn,tag;
}tree[400005];
#define ls p<<1
#define rs p<<1|1
void up(int p){
tree[p].maxn=max(tree[ls].maxn,tree[rs].maxn);
}
void down(int p){
if(tree[p].tag>=0){
tree[ls].lazy=tree[rs].lazy=0;
tree[ls].maxn=tree[rs].maxn=tree[ls].tag=tree[rs].tag=tree[p].tag;
tree[p].tag=-1;
}
if(tree[p].lazy){
tree[ls].lazy+=tree[p].lazy;
tree[rs].lazy+=tree[p].lazy;
tree[ls].maxn+=tree[p].lazy;
tree[rs].maxn+=tree[p].lazy;
tree[p].lazy=0;
}
}
void build(int l,int r,int p,int a[]){
tree[p].tag=-1;
if(l==r){
tree[p].maxn=a[l];
return ;
}
int mid=l+r>>1;
build(l,mid,ls,a);
build(mid+1,r,rs,a);
up(p);
}
void add(int l,int r,int L,int R,int p,int val){
if(L>r||R<l) return ;
if(L<=l&&r<=R){
tree[p].maxn+=val;
tree[p].lazy+=val;
return ;
}
down(p);
int mid=l+r>>1;
if(L<=mid) add(l,mid,L,R,ls,val);
if(R>mid) add(mid+1,r,L,R,rs,val);
up(p);
}
void cover(int l,int r,int L,int R,int p,int val){
if(L>r||R<l) return ;
if(L<=l&&r<=R){
tree[p].maxn=tree[p].tag=val;
tree[p].lazy=0;
return ;
}
down(p);
int mid=l+r>>1;
cover(l,mid,L,R,ls,val);
cover(mid+1,r,L,R,rs,val);
up(p);
}
int query(int l,int r,int L,int R,int p){
if(L<=l&&r<=R) return tree[p].maxn;
int ans=0;
down(p);
int mid=l+r>>1;
if(L<=mid) cmax(ans,query(l,mid,L,R,ls));
if(R>mid) cmax(ans,query(mid+1,r,L,R,rs));
return ans;
}
}Tree;
struct edge{
int v,w,nex;
}e[200005];
int n,tot,head[100005],cnt,dep[100005],sz[100005],fa[100005],tp[100005],p[100005],a[100005],son[100005],id[100005];
void add(int u,int v,int w){
e[++tot].v=v;
e[tot].w=w;
e[tot].nex=head[u];
head[u]=tot;
}
void dfs1(int u,int f){
sz[u]=1;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==f) continue;
dep[v]=dep[u]+1;
fa[v]=u;
p[v]=e[i].w;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
id[u]=++cnt;
tp[u]=t;
a[cnt]=p[u];
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void change1(int x,int y,int val){
int fx=tp[x],fy=tp[y];
while(fx!=fy){
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
Tree.add(1,n,id[fx],id[x],1,val);
x=fa[fx],fx=tp[x];
}
if(id[x]>id[y]) swap(x,y);
Tree.add(1,n,id[x]+1,id[y],1,val);
}
void change2(int x,int y,int val){
int fx=tp[x],fy=tp[y];
while(fx!=fy){
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
Tree.cover(1,n,id[fx],id[x],1,val);
x=fa[fx],fx=tp[x];
}
if(id[x]>id[y]) swap(x,y);
Tree.cover(1,n,id[x]+1,id[y],1,val);
}
int query(int x,int y){
int ans=0,fx=tp[x],fy=tp[y];
while(fx!=fy){
if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
cmax(ans,Tree.query(1,n,id[fx],id[x],1));
x=fa[fx],fx=tp[x];
}
if(id[x]>id[y]) swap(x,y);
cmax(ans,Tree.query(1,n,id[x]+1,id[y],1));
return ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>n;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs1(1,0);
dfs2(1,1);
Tree.build(1,n,1,a);
while(1){
string str;
int x,y,z;
cin>>str;
if(str[0]=='S') break;
cin>>x>>y;
if(str[1]=='h'){
if(dep[e[(x<<1)-1].v]<dep[e[x<<1].v]) z=e[x<<1].v;
else z=e[(x<<1)-1].v;
Tree.cover(1,n,id[z],id[z],1,y);
}
if(str[1]=='o'){
cin>>z;
change2(x,y,z);
}
if(str[1]=='d'){
cin>>z;
change1(x,y,z);
}
if(str[1]=='a'){
cout<<query(x,y)<<endl;
}
}
return 0;
}
/*
things to check:
* Will it MLE?
* Is array big enough?
* Do you need long long?
* Is inf big enough?
* max or min?
* Yes,No or YES,NO?
* Is there anything extra to output?
* Did you Countershoot?
* Have you measured the limit data?
* More measurements should be cleared!!!
*/
估计是树剖挂了。