P1501 [国家集训队]Tree II
https://www.luogu.com.cn/problem/P1501
给定 \(n\) 个节点的树,每个操作是路径的点权都加一个数,路径点权都乘一个数,查询路径点权和(对 \(51061\) 取模),断一条边并加入一条新边(保证合法)
就是用 lct 维护,打反转(换根用)、加法、乘法的懒标记,pushdown 时,还要用到子树大小
其实就和那个线段树模板二一样,因为优先级,乘法标记下传时,子树的加法标记、乘法标记、权值、结果(就是当前的和),都要乘它的乘法标记
而下传加法时,就是让子树的加法标记、结果都加上这个加法标记乘以对应的子树大小,而子树权值就只加它的加法标记就行了
注意模数的平方超过了 int 范围,要开 long long
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define mod 51061
#define N 100005
struct LCT{
struct tr{
tr *son[2],*fa;
LL add,mul;
LL res,val,size;
int tag;
}*null,*pos[N],dizhi[N];
#define ident(tree,fa) (fa->son[1]==tree)
#define notroot(tree) (tree->fa->son[0]==tree||tree->fa->son[1]==tree)
inline void pushup(tr *tree){
tree->res=(tree->son[0]->res+tree->son[1]->res+tree->val)%mod;
tree->size=tree->son[0]->size+tree->son[1]->size+1;
}
inline void connect(tr *tree,tr *fa,int k){fa->son[k]=tree;tree->fa=fa;}
inline void pushdown(tr *tree){
reg LL tmp;
if(tree->tag){
std::swap(tree->son[0]->son[0],tree->son[0]->son[1]);
std::swap(tree->son[1]->son[0],tree->son[1]->son[1]);
tree->son[0]->tag^=1;tree->son[1]->tag^=1;
tree->tag=0;
}
if(tree->mul!=1){
tmp=tree->mul;
tree->son[0]->add*=tmp;tree->son[1]->add*=tmp;
tree->son[0]->add%=mod;tree->son[1]->add%=mod;
tree->son[0]->mul*=tmp;tree->son[1]->mul*=tmp;
tree->son[0]->mul%=mod;tree->son[1]->mul%=mod;
tree->son[0]->val*=tmp;tree->son[1]->val*=tmp;
tree->son[0]->val%=mod;tree->son[1]->val%=mod;
tree->son[0]->res*=tmp;tree->son[1]->res*=tmp;
tree->son[0]->res%=mod;tree->son[1]->res%=mod;
tree->mul=1;
}
if(tree->add){
tmp=tree->add;
tree->son[0]->add+=tmp;tree->son[1]->add+=tmp;
tree->son[0]->add%=mod;tree->son[1]->add%=mod;
tree->son[0]->val+=tmp;tree->son[1]->val+=tmp;
tree->son[0]->val%=mod;tree->son[1]->val%=mod;
tree->son[0]->res+=tmp*tree->son[0]->size;tree->son[1]->res+=tmp*tree->son[1]->size;
tree->son[0]->res%=mod;tree->son[1]->res%=mod;
tree->add=0;
}
}
inline void rotate(tr *tree){
tr *fa=tree->fa,*faa=fa->fa;
pushdown(fa);pushdown(tree);
int k=ident(tree,fa);
connect(tree->son[k^1],fa,k);
tree->fa=faa;
if(notroot(fa)) faa->son[ident(fa,faa)]=tree;
connect(fa,tree,k^1);
pushup(fa);pushup(tree);
}
inline void splay(reg tr *x){
reg tr *fa,*faa;
while(notroot(x)){
fa=x->fa;faa=fa->fa;
if(notroot(fa)) ident(fa,faa)^ident(x,fa)?rotate(x):rotate(fa);
rotate(x);
}
}
inline void access(tr *x){
for(reg tr *lastx=null;x!=null;lastx=x,x=x->fa){
pushdown(x);
splay(x);
x->son[1]=lastx;pushup(x);
}
}
inline void makeroot(tr *x){
access(x);splay(x);
x->tag^=1;std::swap(x->son[0],x->son[1]);
}
inline tr *findroot(tr *x){
access(x);splay(x);
while(x->son[0]!=null) pushdown(x),x=x->son[0];
splay(x);
return x;
}
inline void link(tr *x,tr *y){
makeroot(x);
if(findroot(y)!=x) x->fa=y;
}
inline void cut(tr *x,tr *y){
makeroot(x);
if(findroot(y)!=x||y->fa!=x||y->son[0]!=null) return;
y->fa=x->son[1]=null;
pushup(x);
}
inline void split(tr *x,tr *y){
makeroot(x);
access(y);splay(y);
}
inline void init(int n){
null=&dizhi[0];
for(reg int i=1;i<=n;i++){
pos[i]=&dizhi[i];
dizhi[i].son[0]=dizhi[i].son[1]=null;
dizhi[i].val=dizhi[i].res=1;
dizhi[i].size=dizhi[i].mul=1;
dizhi[i].fa=null;
}
}
}lct;
int main(){
// std::freopen("P1501_2.in","r",stdin);
int n=read(),q=read();
lct.init(n);
int a,b,c,d;
while(--n){
a=read();b=read();
lct.link(lct.pos[a],lct.pos[b]);
}
reg char op;
LCT::tr *tree;
while(q--){
op=getchar();
while(op!='+'&&op!='-'&&op!='/'&&op!='*') op=getchar();
a=read();b=read();
if(op=='+'){
c=read();
lct.split(lct.pos[a],lct.pos[b]);
tree=lct.pos[b];
tree->add+=c;tree->val+=c;tree->res+=c*tree->size;
tree->add%=mod;tree->val%=mod;tree->res%=mod;
}
else if(op=='-'){
c=read();d=read();
lct.cut(lct.pos[a],lct.pos[b]);
lct.link(lct.pos[c],lct.pos[d]);
}
else if(op=='*'){
c=read();
lct.split(lct.pos[a],lct.pos[b]);
tree=lct.pos[b];
tree->add*=c;tree->mul*=c;tree->val*=c;tree->res*=c;
tree->add%=mod;tree->mul%=mod;tree->val%=mod;tree->res%=mod;
}
else{
lct.split(lct.pos[a],lct.pos[b]);
printf("%lld\n",lct.pos[b]->res);
}
}
return 0;
}