PROBLEM
一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
- u v c:将u到v的路径上的点的权值都加上自然数c;
− u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
∗ u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
DATA
1 < = n , q < = 1 0 5 1<=n,q<=10^5 1<=n,q<=105, 0 < = c < = 1 0 4 0<=c<=10^4 0<=c<=104
SOL
直接lct区间打标记就可以了。
注意乘法标记要影响加法的
‘还有,不该pushup的地方不要pushup,否则可能错
比如:
这里2号节点不会再被更新,但3,4号节点的值是错的,所以对2号pushup就错了
//splay不要写错。。
CODE
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
const int N=1e5+10,mod=51061;
int ch[N][2],fa[N],siz[N],s[N],top,rev[N];
ll sum[N],val[N],ad[N],ml[N];
int n,Q;
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
inline bool isroot(int x){return lc(fa[x])!=x&&rc(fa[x])!=x;}
inline bool get(int x){return rc(fa[x])==x;}
inline void pushup(int x){siz[x]=siz[lc(x)]+siz[rc(x)]+1;sum[x]=sum[lc(x)]+sum[rc(x)]+val[x];sum[x]%=mod;}
inline void pushnow(int x,int _ad,int _ml){
ad[x]=(ad[x]*_ml+_ad)%mod;
ml[x]=(ml[x]*_ml)%mod;
sum[x]=(sum[x]*_ml+_ad*siz[x])%mod;
val[x]=(val[x]*_ml+_ad)%mod;
}
//加法和乘法同时出现的时候就要变形式子
inline void pushdown(int x){
if(rev[x]){
swap(lc(x),rc(x));
rev[lc(x)]^=1;rev[rc(x)]^=1;
}
if(ml[x]!=1||ad[x])pushnow(lc(x),ad[x],ml[x]),pushnow(rc(x),ad[x],ml[x]);
rev[x]=ad[x]=0;ml[x]=1ll;
}
inline void rotate(int x){
int y=fa[x],z=fa[y],d=get(x);
fa[x]=z;if(!isroot(y))ch[z][get(y)]=x;
fa[ch[x][d^1]]=y;ch[y][d]=ch[x][d^1];
ch[x][d^1]=y;fa[y]=x;
pushup(y);pushup(x);
}
inline void splay(int x){
s[top=1]=x;int y=x;
//splay写挂了就凉凉。。
while(!isroot(y))y=fa[y],s[++top]=y;
while(top)pushdown(s[top--]);
while(!isroot(x)){
if(!isroot(fa[x]))rotate(get(x)==get(fa[x])? fa[x] : x );
rotate(x);
}
}
inline void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);rc(x)=y;pushup(x);
}
}
inline void makeroot(int x){
access(x);splay(x);rev[x]^=1;
}
inline void split(int x,int y){
makeroot(x);access(y);splay(y);
}
inline void link(int x,int y){
makeroot(x);fa[x]=y;
}
inline void cut(int x,int y){
split(x,y);
lc(y)=fa[x]=0;pushup(y);
}
inline ll query(int x,int y){
split(x,y);
return sum[y];
}
inline void change(int x,int y,int _ad,int _ml){
split(x,y);
pushnow(y,_ad,_ml);
}
inline void dfs(int x){if(!x)return; dfs(lc(x));cout<<x<<' ';dfs(rc(x));}
signed main(){
sf("%d%d",&n,&Q);
for(int i=1;i<=n;++i)siz[i]=1,val[i]=ml[i]=1ll;
for(int i=1;i<n;++i){
int x,y;sf("%d%d",&x,&y);link(x,y);
}
while(Q--){
char c;int x,y,k,p;
sf("\n%c%d%d",&c,&x,&y);
if(c=='+')sf("%d",&k),change(x,y,k,1);
if(c=='-')sf("%d%d",&k,&p),cut(x,y),link(k,p);
if(c=='*')sf("%d",&k),change(x,y,0,k);
if(c=='/')pf("%lld\n",query(x,y));
}
return 0;
}