不知道为啥把 link 里面的 findroot 去掉就对了……没想通为啥
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
const int mod=51061;
inline int Add(int x,int y){return (x+y)%mod;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
#define gc() getchar()
inline int read(){
int s=0,w=1;
char ch=gc();
while(!isdigit(ch)){
if(ch=='-')w=-1;
ch=gc();
}
while(isdigit(ch)){
s=s*10-'0'+ch;
ch=getchar();
}
return s*w;
}
struct LinkCutTree{
bool rev[N];
int ch[N][2],f[N],mul[N],add[N];
int sum[N],val[N],siz[N],st[N];
inline void pushup(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];sum[x]%=mod;siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
inline void pushr(int x){int t=ch[x][0];ch[x][0]=ch[x][1];ch[x][1]=t;rev[x]^=1;}
inline void pushm(int x,int v){sum[x]=Mul(sum[x],v);val[x]=Mul(val[x],v);mul[x]=Mul(mul[x],v);add[x]=Mul(add[x],v);}
inline void pusha(int x,int v){sum[x]=Add(sum[x],Mul(siz[x],v));add[x]=Add(add[x],v);val[x]=Add(val[x],v);}
inline void pushdown(int x){
if(mul[x]!=1){
pushm(ch[x][0],mul[x]);
pushm(ch[x][1],mul[x]);
mul[x]=1;
}
if(add[x]){
pusha(ch[x][0],add[x]);
pusha(ch[x][1],add[x]);
add[x]=0;
}
if(rev[x]){
if(ch[x][0])pushr(ch[x][0]);
if(ch[x][1])pushr(ch[x][1]);
rev[x]^=1;
}
}
inline bool nroot(int x){return ch[f[x]][1]==x||ch[f[x]][0]==x;}
void rotate(int x){
int y=f[x],z=f[y],k=(ch[y][1]==x),w=ch[x][k^1];
if(nroot(y))ch[z][ch[z][1]==y]=x;ch[x][k^1]=y;ch[y][k]=w;
if(w)f[w]=y;f[y]=x;f[x]=z;pushup(y);pushup(x);
}
void splay(int x){
int y=x,z=0;
st[++z]=y;
while(nroot(y)) st[++z]=y=f[y];
while(z) pushdown(st[z--]);
while(nroot(x)){
y=f[x];z=f[y];
if(nroot(y))rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int y=0;x;y=x,x=f[x]){
splay(x);ch[x][1]=y;pushup(x);
}
}
inline void makeroot(int x){
access(x);
splay(x);
pushr(x);
}
int findroot(int x){
access(x);splay(x);
while(ch[x][0])pushdown(x),x=ch[x][0];
splay(x);return x;
}
void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y){
makeroot(x);
//if(findroot(y)!=x)
f[x]=y;
}
void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&f[y]==x&&!ch[y][0]){
f[y]=ch[x][1]=0;
pushup(x);
}
}
void changeadd(int x,int y,int v){
split(x,y);
pusha(y,v);
}
void changemul(int x,int y,int v){
split(x,y);
pushm(y,v);
}
int query(int x,int y){
split(x,y);
return sum[y];
}
}T;
int n,q;
int main(){
n=read();q=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
T.link(u,v);
}
for(int i=1;i<=n;++i)T.mul[i]=T.val[i]=T.siz[i]=1;
for(int kkk=1;kkk<=q;++kkk){
char opt;
cin>>opt;
if(opt=='+'){
int u=read();
int v=read();
int c=read();
T.changeadd(u,v,c);
}
else if(opt=='-'){
int u1=read();
int v1=read();
int u2=read();
int v2=read();
T.cut(u1,v1);
T.link(u2,v2);
}
else if(opt=='*'){
int u=read();
int v=read();
int c=read();
T.changemul(u,v,c);
}
else {
int u=read(),v=read();
printf("%d\n",T.query(u,v));
}
}
return 0;
}