#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=100005;
const ll
moder=(ll)51061;
int n,q;
struct LCT{
int pre,son[2];
bool rev,ifplus,ifmulti;
ll sum,num,plus,multi,sz;
}tree[N];
bool isroot(int x){
return tree[tree[x].pre].son[0]!=x &&
tree[tree[x].pre].son[1]!=x;
}
void up(int x){
if (x){
int l=tree[x].son[0],r=tree[x].son[1];
tree[x].sum=tree[x].num,tree[x].sz=(ll)1;
if (l)
tree[x].sum=(tree[x].sum+tree[l].sum)%moder,
tree[x].sz=(tree[x].sz+tree[l].sz)%moder;
if (r)
tree[x].sum=(tree[x].sum+tree[r].sum)%moder,
tree[x].sz=(tree[x].sz+tree[r].sz)%moder;
}
}
void calcplus(int x,ll num){
tree[x].plus=(tree[x].plus+num)%moder;
tree[x].num=(tree[x].num+num)%moder;
tree[x].sum=(tree[x].sum+(num*tree[x].sz)%moder)%moder;
tree[x].ifplus=1;
}
void calcmulti(int x,ll num){
tree[x].multi=(tree[x].multi*num)%moder;
tree[x].plus=(tree[x].plus*num)%moder;
tree[x].num=(tree[x].num*num)%moder;
tree[x].sum=(tree[x].sum*num)%moder;
tree[x].ifmulti=1;
}
void down(int x){
int L=tree[x].son[0],R=tree[x].son[1];
if (tree[x].rev){
swap(tree[x].son[0],tree[x].son[1]);
tree[L].rev^=1,tree[R].rev^=1;
tree[x].rev=0;
}
if (tree[x].ifmulti){
calcmulti(L,tree[x].multi);
calcmulti(R,tree[x].multi);
tree[x].multi=(ll)1;
tree[x].ifmulti=0;
}
if (tree[x].ifplus){
calcplus(L,tree[x].plus);
calcplus(R,tree[x].plus);
tree[x].plus=tree[x].ifplus=0;
}
}
void Rotate(int x){
int y=tree[x].pre,z=tree[y].pre,l,r;
if (tree[y].son[0]==x) l=0; else l=1;
r=l^1;
if (!isroot(y))
if (tree[z].son[0]==y) tree[z].son[0]=x;
else tree[z].son[1]=x;
tree[x].pre=z,tree[y].pre=x;
tree[y].son[l]=tree[x].son[r];
tree[tree[x].son[r]].pre=y;
tree[x].son[r]=y;
up(y);
}
int stk[N];
void splay(int x){
int top=1;stk[1]=x;
for (int i=x;!isroot(i);i=tree[i].pre)
stk[++top]=tree[i].pre;
while (top) down(stk[top--]);
while (!isroot(x)){
int y=tree[x].pre,z=tree[y].pre;
if (!isroot(y))
if (tree[z].son[0]==y^tree[y].son[0]==x) Rotate(x);
else Rotate(y);
Rotate(x);
}
up(x);
}
void access(int x){
for (int t=0;x;t=x,x=tree[x].pre)
splay(x),tree[x].son[1]=t,up(x);
}
void makeroot(int x){
access(x),splay(x);
tree[x].rev^=1;
}
void split(int x,int y){
makeroot(x);
access(y),splay(y);
}
void link(int x,int y){
makeroot(x);
tree[x].pre=y;
}
void cut(int x,int y){
split(x,y);
tree[y].son[0]=tree[x].pre=0;
up(y);
}
ll querysum(int x,int y){
split(x,y);
return tree[y].sum;
}
void updateplus(int x,int y,ll num){
split(x,y);
calcplus(y,num);
}
void updatemulti(int x,int y,ll num){
split(x,y);
calcmulti(y,num);
}
int main(){
n=read(),q=read();
for (int i=1;i<=n;i++)
tree[i].multi=tree[i].num=tree[i].sum=tree[i].sz=(ll)1;
for (int i=1;i<n;i++) link(read(),read());
char opt[2]; int u,v;ll c;
while (q--){
scanf("%s",opt);
if (opt[0]=='-')
cut(read(),read()),link(read(),read());
else{
u=read(),v=read();
if (opt[0]=='/') printf("%lld\n",querysum(u,v));
else c=(ll)read();
if (opt[0]=='+') updateplus(u,v,c);
if (opt[0]=='*') updatemulti(u,v,c);
}
}
return 0;
}