看来这个LCT板子并没有什么问题

 #include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL md=;
namespace LCT
{
struct Node
{
Node *ch[],*fa;
bool rev;
LL addv,mulv;
LL dat,sum,sz;
void padd(LL x)
{
addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md;
}
void pmul(LL x)
{
addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md;
}
void upd()
{
sum=((ch[]?ch[]->sum:)+(ch[]?ch[]->sum:)+dat)%md;
sz=(ch[]?ch[]->sz:)+(ch[]?ch[]->sz:)+;
}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
}nodes[];
LL mem;
Node *getnode()
{
return nodes+(mem++);
}
bool isroot(Node *x)
{
return (!x->fa)||((x->fa->ch[]!=x)&&(x->fa->ch[]!=x));
}
bool gson(Node *o) {return o==o->fa->ch[];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
void rotate(Node *o,bool d)
//在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
{
Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
o->ch[!d]=k->ch[d];k->ch[d]=o;
o->upd();k->upd();
k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o;
}
Node *st[];LL top;
void solvetag(Node *o)
{
while(!isroot(o)) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
Node *fa,*fafa;bool d1,d2;
while(!isroot(o))
{
fa=o->fa;d1=(o==fa->ch[]);
if(isroot(fa)) rotate(fa,d1);
else
{
fafa=o->fa->fa;d2=(fa==fafa->ch[]);//要保证fa不是root之后才能获取这两个值,曾错过
if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
}
}
}
void access(Node *o)
{
for(Node *lst=NULL;o;lst=o,o=o->fa)
{
splay(o);//此处不pushdown是由于splay中保证进行过了
o->ch[]=lst;o->upd();//注意upd
}
}
Node *gtop(Node *o)
{
access(o);splay(o);
for(;o->ch[];o=o->ch[],o->pd());//此处不在开始前pushdown(o)是由于splay中保证进行过了
splay(o);return o;//听说这里不splay一下也很难卡掉
}
void mtop(Node *o) {access(o);splay(o);o->rev^=;}
void link(Node *x,Node *y)
{
if(gtop(x)==gtop(y)) return;
mtop(y);y->fa=x;
}
void cut(Node *x,Node *y)
{
mtop(x);access(y);splay(y);
if(y->ch[]!=x||x->ch[]) return;//如果x、y之间直接有边,那么上面一行的操作之后应当是x与y在单独一棵splay中,那么一定保证y左子节点是x且x没有右子节点
x->fa=y->ch[]=NULL;//注意,改的是x的父亲和y的子节点(虽然x的确是树的根,但是此时在splay上是y的子节点,不能搞混)
y->upd();//注意
}
LL query(Node *x,Node *y)
{
mtop(x);access(y);splay(y);
//if(gtop(y)!=x) return 0;//此题保证x与y连通,不需要
return y->sum;
}
void add(Node *x,Node *y,LL t)
{
mtop(x);access(y);splay(y);
y->padd(t);
}
void mul(Node *x,Node *y,LL t)
{
mtop(x);access(y);splay(y);
y->pmul(t);
}
}
LCT::Node *nd[];
LL n,q;char tmp[];
int main()
{
LL i,x,y,t,x2,y2;
scanf("%lld%lld",&n,&q);
for(i=;i<=n;i++)
{
nd[i]=LCT::getnode();
nd[i]->mulv=;nd[i]->dat=nd[i]->sum=;nd[i]->sz=;
}
for(i=;i<n;i++)
{
scanf("%lld%lld",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%lld%lld",&x,&y);
printf("%lld\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}

压行后:

 #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL md=;
namespace LCT
{
struct Node
{
Node *ch[],*fa;
bool rev;
LL addv,mulv;
LL dat,sum,sz;
void padd(LL x)
{
addv=(addv+x)%md;dat=(dat+x)%md;sum=(sum+x*sz)%md;
}
void pmul(LL x)
{
addv=addv*x%md;mulv=mulv*x%md;dat=dat*x%md;sum=sum*x%md;
}
void upd()
{
sum=((ch[]?ch[]->sum:)+(ch[]?ch[]->sum:)+dat)%md;
sz=(ch[]?ch[]->sz:)+(ch[]?ch[]->sz:)+;
}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
}nodes[];
LL mem;
Node *getnode()
{
return nodes+(mem++);
}
bool isroot(Node *x)
{
return (!x->fa)||((x->fa->ch[]!=x)&&(x->fa->ch[]!=x));
}
bool gson(Node *o) {return o==o->fa->ch[];}//获得是父亲的左儿子(返回0)还是右儿子(1),要求保证存在父亲
void rotate(Node *o,bool d)
//在o子树中执行d=0左旋,d=1右旋,在旋转前不标记下传,并将o父节点的对应子节点由o变为需要值,要求保证存在子树(!d)
{
Node *k=o->ch[!d];if(!isroot(o)) o->fa->ch[gson(o)]=k;//注意这一句修改o父节点的要写在前面,曾经出过错调了一会
o->ch[!d]=k->ch[d];k->ch[d]=o;
o->upd();k->upd();
k->fa=o->fa;o->fa=k;if(o->ch[!d]) o->ch[!d]->fa=o;
}
Node *st[];LL top;
void solvetag(Node *o)
{
while(!isroot(o)) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
Node *fa,*fafa;bool d1,d2;
while(!isroot(o))
{
fa=o->fa;d1=(o==fa->ch[]);
if(isroot(fa)) rotate(fa,d1);
else
{
fafa=o->fa->fa;d2=(fa==fafa->ch[]);//要保证fa不是root之后才能获取这两个值,曾错过
if(d1==d2) rotate(fafa,d1),rotate(fa,d1);//zig-zig,两次相同方向的单旋,先把父亲转上去,再把自己转上去
else rotate(fa,d1),rotate(fafa,d2);//zig-zag,两次相反方向的单旋,连续两次把自己转上去
}
}
}
void access(Node *o)
{
for(Node *lst=NULL;o;lst=o,o=o->fa)
{
splay(o);
o->ch[]=lst;o->upd();
}
}
Node *gtop(Node *o)
{
access(o);splay(o);
for(;o->ch[];o=o->ch[],o->pd());
splay(o);return o;
}
void mtop(Node *o) {access(o);splay(o);o->rev^=;}
void split(Node *x,Node *y) {mtop(x);access(y);splay(y);}
void link(Node *x,Node *y) {mtop(y);y->fa=x;}
void cut(Node *x,Node *y) {split(x,y);x->fa=y->ch[]=NULL;y->upd();}
LL query(Node *x,Node *y) {split(x,y);return y->sum;}
void add(Node *x,Node *y,LL t) {split(x,y);y->padd(t);}
void mul(Node *x,Node *y,LL t) {split(x,y);y->pmul(t);}
}
LCT::Node *nd[];
LL n,q;char tmp[];
int main()
{
LL i,x,y,t,x2,y2;
scanf("%lld%lld",&n,&q);
for(i=;i<=n;i++)
{
nd[i]=LCT::getnode();
nd[i]->mulv=;nd[i]->dat=nd[i]->sum=;nd[i]->sz=;
}
for(i=;i<n;i++)
{
scanf("%lld%lld",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%lld%lld%lld",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%lld%lld",&x,&y);
printf("%lld\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}

重新打了一个板子

 #include<cstdio>
#include<algorithm>
#include<cassert>
#define md 51061
using namespace std;
typedef long long LL;
int Add(int a,int b) {return (a+b)%md;}
int Add(int a,int b,int c) {return (a+b+c)%md;}
int Mul(int a,int b) {return LL(a)*b%md;}
namespace LCT
{
const int N=;
struct Node
{
Node *ch[],*fa;
bool rev;
int addv,mulv;
int dat,sum,sz;
void upd()
{
sum=Add((ch[]?ch[]->sum:),dat,(ch[]?ch[]->sum:));
sz=(ch[]?ch[]->sz:)++(ch[]?ch[]->sz:);
}
void padd(int x) {addv=Add(addv,x);dat=Add(dat,x);sum=Add(sum,Mul(x,sz));}
void pmul(int x) {addv=Mul(addv,x);mulv=Mul(mulv,x);dat=Mul(dat,x);sum=Mul(sum,x);}
void pd()
{
if(rev)
{
swap(ch[],ch[]);
if(ch[]) ch[]->rev^=;
if(ch[]) ch[]->rev^=;
rev=;
}
if(mulv!=)
{
if(ch[]) ch[]->pmul(mulv);
if(ch[]) ch[]->pmul(mulv);
mulv=;
}
if(addv)
{
if(ch[]) ch[]->padd(addv);
if(ch[]) ch[]->padd(addv);
addv=;
}
}
bool isroot() {return (!fa)||(this!=fa->ch[]&&this!=fa->ch[]);}
bool gson() {return this==fa->ch[];}
void rot()//将自身向上旋,要求已经完成下传标记
{
bool d=gson();Node *f=fa;
fa=f->fa;if(!f->isroot()) f->fa->ch[f->gson()]=this;
f->ch[d]=ch[!d];if(ch[!d]) ch[!d]->fa=f;
f->fa=this;ch[!d]=f;
f->upd();upd();
}
}nodes[N+];
Node *st[N+];int top;
int mem;
Node *getnode()
{
Node *t=nodes+mem++;t->mulv=;t->sz=;t->dat=t->sum=;
return t;
}
void solvetag(Node *o)
{
while(!o->isroot()) st[++top]=o,o=o->fa;
st[++top]=o;
while(top) st[top--]->pd();
}
void splay(Node *o)
{
solvetag(o);
for(;!o->isroot();o->rot())
if(!o->fa->isroot())
o->gson()==o->fa->gson()?o->fa->rot():o->rot();
}
void acc(Node *o)
{
for(Node *lst=;o;lst=o,o=o->fa)
splay(o),o->ch[]=lst,o->upd();
}
void mtop(Node *o) {acc(o);splay(o);o->rev^=;}
void link(Node *x,Node *y) {mtop(y);y->fa=x;}
void cut(Node *x,Node *y) {mtop(x);acc(y);splay(y);x->fa=y->ch[]=;y->upd();}
int query(Node *x,Node *y) {mtop(x);acc(y);splay(y);return y->sum;}
void add(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->padd(t);}
void mul(Node *x,Node *y,int t) {mtop(x);acc(y);splay(y);y->pmul(t);}
}
LCT::Node *nd[];
int n,q;char tmp[];
int main()
{
int i,x,y,t,x2,y2;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++) nd[i]=LCT::getnode();
for(i=;i<n;i++)
{
scanf("%d%d",&x,&y);
LCT::link(nd[x],nd[y]);
}
while(q--)
{
scanf("%s",tmp);
switch(tmp[])
{
case '+':
scanf("%d%d%d",&x,&y,&t);
LCT::add(nd[x],nd[y],t);
break;
case '-':
scanf("%d%d%d%d",&x,&y,&x2,&y2);
LCT::cut(nd[x],nd[y]);LCT::link(nd[x2],nd[y2]);
break;
case '*':
scanf("%d%d%d",&x,&y,&t);
LCT::mul(nd[x],nd[y],t);
break;
case '/':
scanf("%d%d",&x,&y);
printf("%d\n",LCT::query(nd[x],nd[y]));
}
}
return ;
}
05-11 20:42