lct维护一些基本的树链信息 注意的地方是要类似线段树一样 先维护乘标记 再维护加标记
另外修改树链 u,v的信息时 把u,v 分(split)出来 要在最后被splay上来的那个点修改才能保证正确性
#include<bits/stdc++.h>
#define R register int
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
#define ml(x) x*=c;x%=mod
#define al(x,c) x+=c;x%=mod
using namespace std;
const int N = 1e5+10;
typedef long long ll;
const ll mod = 51061;
inline int in(){
int w=0,x=0;char c=0;
while(c>'9'||c<'0') w|=c=='-',c=getchar();
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
ll v[N],siz[N],add[N],mul[N],s[N];
int f[N],c[N][2],st[N];
bool r[N];
inline bool nroot(R x){
return c[f[x]][0]==x||c[f[x]][1]==x;
}
I pushup(R x){
s[x]=s[lc]+s[rc]+v[x];
siz[x]=siz[lc]+siz[rc]+1;
}
I pushr(R x){
swap(lc,rc);r[x]^=1;
}
I pushm(R x,ll c){
ml(s[x]);ml(v[x]);ml(mul[x]);ml(add[x]);
}
I pusha(R x,ll c){
al(s[x],c*siz[x]);al(v[x],c);al(add[x],c);
}
I pushdown(R x){
if(mul[x]!=1){
if(lc) pushm(lc,mul[x]);
if(rc) pushm(rc,mul[x]);
mul[x]=1;
}
if(add[x]!=0){
if(lc) pusha(lc,add[x]);
if(rc) pusha(rc,add[x]);
add[x]=0;
}
if(r[x]){
if(lc) pushr(lc);
if(rc) pushr(rc);
r[x]=0;
}
}
I rotate(R x){
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][k^1];
if(nroot(y)) c[z][c[z][1]==y]=x;c[x][k^1]=y;c[y][k]=w;
if(w) f[w]=y;f[y]=x;f[x]=z;
pushup(y);
}
I splay(R x){
R 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((c[y][0]==x)^(c[z][0]==y)?x:y);
rotate(x);
}
pushup(x);
}
I access(R x){
for(R y=0;x;x=f[y=x])
splay(x),rc=y,pushup(x);
}
I makeroot(R x){
access(x);splay(x);
pushr(x);
}
inline int findroot(R x){
access(x);splay(x);
while(lc) pushdown(x),x=lc;
splay(x);
return x;
}
I split(R x,R y){
makeroot(x);
access(y);splay(y);
}
I link(R x,R y){
makeroot(x);
if(findroot(y)!=x) f[x]=y;
}
I cut(R x,R y){
makeroot(x);
if(findroot(y)==x&&f[y]==x&&!c[y][0]){
f[y]=c[x][1]=0;
pushup(x);
}
}
int main(){
int n,q;
n=in();q=in();
for(int i = 1; i <= n; i++) v[i]=siz[i]=mul[i]=1;
for(int i = 1; i <= n-1; i++){
int u,v;
scanf("%d%d",&u,&v);
link(u,v);
}
char op[3];
int a,b,c,d;
for(int i = 1; i <= q; i++){
scanf("%s%d%d",op,&a,&b);
if(op[0]=='+'){
scanf("%d",&c);
split(a,b);
pusha(b,c);
}else if(op[0]=='-'){
scanf("%d%d",&c,&d);
cut(a,b);
link(c,d);
}else if(op[0]=='*'){
scanf("%d",&c);
split(a,b);
pushm(b,c);
}else{
split(a,b);
printf("%lld\n",s[b]%mod);
}
}
return 0;
}