const int MAXN=1e5+5,Mod=51061;
struct Link_Cut_tree{
int ch[MAXN][2],fa[MAXN],sz[MAXN],w[MAXN],s[MAXN];
int mul_tag[MAXN],add_tag[MAXN];
int Stack[MAXN],top;
bool flip[MAXN];
#define lch(k) ch[k][0]
#define rch(k) ch[k][1]
void node_init(int k,int v){
ch[k][0]=ch[k][1]=fa[k]=0;
sz[k]=1;
w[k]=s[k]=v;
mul_tag[k]=1,add_tag[k]=0,flip[k]=false;
}
void push_up(int k){
s[k]=(s[lch(k)]+s[rch(k)]+w[k])%Mod;
sz[k]=sz[lch(k)]+sz[rch(k)]+1;
}
void push_flip(int k){
swap(lch(k),rch(k));
flip[k]^=1;
}
void push_mul(int k,int v){
s[k]=1LL*s[k]*v%Mod;
w[k]=1LL*w[k]*v%Mod;
add_tag[k]=1LL*add_tag[k]*v%Mod;
mul_tag[k]=1LL*mul_tag[k]*v%Mod;
}
void push_add(int k,int v){
s[k]=(s[k]+1LL*sz[k]*v)%Mod;
w[k]=(w[k]+v)%Mod;
add_tag[k]=(add_tag[k]+v)%Mod;
}
void push_down(int k){
if(flip[k]){
push_flip(lch(k));
push_flip(rch(k));
flip[k]=0;
}
if(mul_tag[k]!=1){
push_mul(lch(k),mul_tag[k]);
push_mul(rch(k),mul_tag[k]);
mul_tag[k]=1;
}
if(add_tag[k]){
push_add(lch(k),add_tag[k]);
push_add(rch(k),add_tag[k]);
add_tag[k]=0;
}
}
bool isroot(int k){
return lch(fa[k])!=k&&rch(fa[k])!=k;
}
void rotate(int k){
int pa=fa[k],ga=fa[pa],dir;
dir=ch[pa][0]==k?0:1;
if(!isroot(pa))ch[ga][ch[ga][0]==pa?0:1]=k;
fa[k]=ga,fa[pa]=k;
if(ch[k][dir^1])fa[ch[k][dir^1]]=pa;
ch[pa][dir]=ch[k][dir^1],ch[k][dir^1]=pa;
push_up(pa);
}
void splay(int k){
Stack[top=1]=k;
for(int i=k;!isroot(i);i=fa[i])Stack[++top]=fa[i];
while(top)push_down(Stack[top--]);
while(!isroot(k)){
int pa=fa[k],ga=fa[pa];
if(!isroot(pa))rotate((ch[pa][0]==k)^(ch[ga][0]==pa)?k:pa);
rotate(k);
}
push_up(k);
}
void access(int k){
for(int t=0;k;t=k,k=fa[k]){
splay(k);
ch[k][1]=t;
push_up(k);
}
}
void makeroot(int k){
access(k);
splay(k);
push_flip(k);
}
int findroot(int k){
access(k);splay(k);
push_down(k);
while(ch[k][0])push_down(k=ch[k][0]);
splay(k);
return k;
}
void split(int u,int v){
makeroot(u);
access(v);
splay(v);
}
void link(int u,int v){
makeroot(u);
if(findroot(v)!=u)fa[u]=v;
}
void cut(int u,int v){
split(u,v);
if(ch[v][0]==u&&ch[u][1]==0){
ch[v][0]=fa[u]=0;
push_up(v);
}
}
void update_add(int u,int v,int val){
split(u,v);
push_add(v,val);
}
void update_mul(int u,int v,int val){
split(u,v);
push_mul(v,val);
}
int query_sum(int u,int v){
split(u,v);
return s[v];
}
}LCT;
int main()
{
int n=read_int(),m=read_int();
_rep(i,1,n)
LCT.node_init(i,1);
_for(i,1,n){
int u=read_int(),v=read_int();
LCT.link(u,v);
}
while(m--){
char opt=get_char();
int u=read_int(),v=read_int();
if(opt=='+')
LCT.update_add(u,v,read_int());
else if(opt=='-'){
LCT.cut(u,v);
u=read_int(),v=read_int();
LCT.link(u,v);
}
else if(opt=='*')
LCT.update_mul(u,v,read_int());
else
enter(LCT.query_sum(u,v));
}
return 0;
}