题意:
支持一颗动态树,可以路径乘,加。
题解:LCT
乘一个点只需要把addtag乘,pushdown的时候先pushdown乘的标记就行了。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned int uint;
struct IO{
streambuf *ib,*ob;
inline void init(){
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
ib=cin.rdbuf();ob=cout.rdbuf();
}
inline int read(){
static char ch;static int i,f;
ch=ib->sbumpc();i=0,f=1;
while(!isdigit(ch)){
if(ch==-1)return false;
if(ch=='-')f=-1;
ch=ib->sbumpc();
}
while(isdigit(ch)){
i=(i+(i<<2)<<1)+ch-'0';
ch=ib->sbumpc();
}
return ((f>0)?i:-i);
}
inline void W(int x){
static int buf[50];
if(!x){ob->sputc('0');return;}
if(x<0){ob->sputc('-');x=-x;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
}
}io;
const int Maxn=1e5+50,INF=0x3f3f3f3f;
uint n,m,mod=51061;
struct node
{
node *fa,*lc,*rc;
uint sze,sum,val,revtag,multag,addtag;
node():fa(NULL),lc(NULL),rc(NULL),sze(1){}
inline void upt(){
sze=(lc?lc->sze:0)+(rc?rc->sze:0)+1;
sum=((lc?lc->sum:0)+(rc?rc->sum:0)+val)%mod;
}
inline void rev(){
swap(lc,rc);revtag^=1;
}
inline void add(uint v){
sum=(sum+sze*v)%mod;
val=(val+v)%mod;
addtag=(addtag+v)%mod;
}
inline void mul(uint v){
addtag=addtag*v%mod;
sum=sum*v%mod;
val=val*v%mod;
multag=multag*v%mod;
}
inline void pushdown(){
if(revtag){
if(lc)lc->rev();
if(rc)rc->rev();
revtag=0;
}
if(multag!=1){
if(lc)lc->mul(multag);
if(rc)rc->mul(multag);
multag=1;
}
if(addtag){
if(lc)lc->add(addtag);
if(rc)rc->add(addtag);
addtag=0;
}
}
};
struct LCT{
node Pool[Maxn],*pool,*des,*tr[Maxn];
LCT(){pool=Pool;}
inline bool isroot(node *x){
return (!x->fa)||(x->fa->lc!=x&&x->fa->rc!=x);
}
inline bool which(node *x){
return x->fa->lc==x;
}
inline void rotate(node *x){
node *y=x->fa,*z=y->fa;
if(!isroot(y))(z->lc==y?z->lc:z->rc)=x;
x->fa=z;y->fa=x;
if(y->lc==x){
node *b=x->rc;
x->rc=y;y->lc=b;
if(b)b->fa=y;
}
else{
node *b=x->lc;
x->lc=y;y->rc=b;
if(b)b->fa=y;
}
y->upt();x->upt();
}
inline void splay(node *x){
static node *que[Maxn];static int tail=0;
que[tail=1]=x;
for(node *y=x;!isroot(y);y=y->fa)que[++tail]=y->fa;
for(int i=tail;i>=1;i--)que[i]->pushdown();
while(!isroot(x)){
node *y=x->fa;
if(!isroot(y))(which(y)^which(x))?(rotate(x)):(rotate(y));
rotate(x);
}
}
inline void access(node *x){
for(node *y=NULL;x;y=x,x=x->fa){
splay(x);x->rc=y;
if(y)y->fa=x;
x->upt();
}
}
inline void makeroot(node *x){
access(x);splay(x);x->rev();
}
inline void link(node *x,node *fa){
makeroot(x);x->fa=fa;
}
inline void cut(node *x,node *fa){
makeroot(fa);access(x);splay(x);
x->lc->fa=NULL;x->lc=NULL;x->upt();
}
inline void addval(node *x,node *y,uint val){
makeroot(x);access(y);splay(y);
y->add(val);
}
inline void mulval(node *x,node *y,uint val){
makeroot(x);access(y);splay(y);
y->mul(val);
}
inline void query(node *x,node *y){
makeroot(x);access(y);splay(y);
io.W(y->sum);io.ob->sputc('\n');
}
}lct;
int main(){
io.init();n=io.read();m=io.read();
for(int i=1;i<=n;i++)lct.tr[i]=++lct.pool,lct.tr[i]->multag=1;
for(int i=1;i<n;i++){
int x=io.read(),y=io.read();
lct.link(lct.tr[x],lct.tr[y]);
}
for(int i=1;i<=n;i++){
lct.addval(lct.tr[i],lct.tr[i],1);
}
for(int i=1;i<=m;i++){
static char ch[8];
cin>>(ch+1);int x=io.read(),y=io.read();
if(ch[1]=='*'){
int c=io.read()%mod;
lct.mulval(lct.tr[x],lct.tr[y],c);
}
else if(ch[1]=='+'){
int c=io.read()%mod;
lct.addval(lct.tr[x],lct.tr[y],c);
}
else if(ch[1]=='/'){
lct.query(lct.tr[x],lct.tr[y]);
}
else{
lct.cut(lct.tr[x],lct.tr[y]);
x=io.read();y=io.read();
lct.link(lct.tr[x],lct.tr[y]);
}
}
}