题目大意:给定一棵结点初始值为1的无根树,要求支持以下操作:链加,链乘,链求和,断一条边连一条边保证还是一棵树
真·LCT模板题,标记最好是直接推给儿子(也就是标记跟自己没关系),推标记要先推乘后推加。
反转时不能直接把标记变成false
在Splay之前要调用To_pushdown(即把点o的祖先的标记都推下来)
#include <cstdio>
#include <algorithm>
#define N 100005
#define MOD 51061
using namespace std;
#define int long long
struct Node {
Node *ch[2],*pa;
int s,val,sum,add_mark,times_mark;
bool rev_mark;
int dir() {return pa->ch[0]==this ? 0 : pa->ch[1]==this ? 1 : -1;}
Node();
void pushdown();
void maintain();
void add(int x);
void rev();
void times(int x);
}*null=new Node(),p[N];
Node :: Node() {
s=null ? 1 : 0;
val=sum=s;
ch[0]=ch[1]=pa=null;
add_mark=0;
times_mark=1;
rev_mark=false;
}
void Node :: pushdown() {
if(this==null) return ;
if(times_mark!=1) {
ch[0]->times(times_mark);
ch[1]->times(times_mark);
times_mark=1;
}
if(add_mark) {
ch[0]->add(add_mark);
ch[1]->add(add_mark);
add_mark=0;
}
if(rev_mark) {
ch[0]->rev();
ch[1]->rev();
rev_mark=false;
}
return ;
}
void Node :: maintain() {
if(this==null) return ;
s=ch[0]->s+ch[1]->s+1;
sum=(ch[0]->sum+ch[1]->sum+val)%MOD;
return ;
}
void Node :: add(int x) {
if(this==null) return ;
val=(val+x)%MOD;
add_mark=(add_mark+x)%MOD;
sum=(sum+x*s)%MOD;
return ;
}
void Node :: times(int x) {
if(this==null) return ;
times_mark=(times_mark*x)%MOD;
val=(val*x)%MOD;
sum=(sum*x)%MOD;
add_mark=(add_mark*x)%MOD;
return ;
}
void Node :: rev() {
if(this==null) return ;
rev_mark=!rev_mark;
swap(ch[0],ch[1]);
return ;
}
void To_pushdown(Node* o) {
if(~(o->dir())) To_pushdown(o->pa);
o->pushdown();
return ;
}
void Rotate(Node* o,int d) {
Node* k=o->ch[d^1]; int d2;
o->ch[d^1]=k->ch[d]; k->ch[d]->pa=o;
k->ch[d]=o;
o->maintain(); k->maintain();
if(~(d2=o->dir())) o->pa->ch[d2]=k;
k->pa=o->pa; o->pa=k;
return ;
}
void Splay(Node* o) {
int d; To_pushdown(o);
while(~(d=o->dir())) {
if(d==o->pa->dir()) Rotate(o->pa->pa,d^1);
Rotate(o->pa,d^1);
}
return ;
}
void Access(Node* o) {
Node* p=null;
while(o!=null) {
Splay(o);
o->ch[1]=p; o->maintain();
p=o;
o=o->pa;
}
return ;
}
void Move_to_root(Node* o) {
Access(o); Splay(o);
o->rev();
return ;
}
void Link(Node* x,Node* y) {
Move_to_root(x);
x->pa=y;
return ;
}
void Cut(Node* x,Node* y) {
Move_to_root(x);
Access(y); Splay(y);
y->ch[0]=null; y->maintain();
x->pa=null;
return ;
}
main() {
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++) {
int x,y;
scanf("%lld%lld",&x,&y);
Link(&p[x],&p[y]);
}
while(m--) {
char mode[2];
scanf("%s",mode);
if(mode[0]=='+') {
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
Move_to_root(&p[x]);
Access(&p[y]); Splay(&p[y]);
p[y].add(z);
}
if(mode[0]=='-') {
int x,y;
scanf("%lld%lld",&x,&y);
Cut(&p[x],&p[y]);
scanf("%lld%lld",&x,&y);
Link(&p[x],&p[y]);
}
if(mode[0]=='*') {
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
Move_to_root(&p[x]);
Access(&p[y]); Splay(&p[y]);
p[y].times(z);
}
if(mode[0]=='/') {
int x,y;
scanf("%lld%lld",&x,&y);
Move_to_root(&p[x]);
Access(&p[y]); Splay(&p[y]);
printf("%lld\n",p[y].sum%MOD);
}
}
return 0;
}