bzoj2631: tree
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define mod 51061 #define maxn 100005 #define ll unsigned int using namespace std; int n,q,fa[maxn],son[maxn][2],size[maxn]; bool rev[maxn]; ll val[maxn],lazyc[maxn],lazyh[maxn],sum[maxn]; struct date{ int which(int x){ return son[fa[x]][1]==x; } bool isroot(int x){ return son[fa[x]][0]!=x&&son[fa[x]][1]!=x; } void update(int x){ size[x]=size[son[x][0]]+size[son[x][1]]+1; sum[x]=val[x]%mod; if (son[x][0]) sum[x]=(sum[x]+sum[son[x][0]])%mod; if (son[x][1]) sum[x]=(sum[x]+sum[son[x][1]])%mod; } void jia(int x,ll y){ lazyh[x]=(lazyh[x]+y)%mod; val[x]=(val[x]+y)%mod; sum[x]=(sum[x]+size[x]*y%mod)%mod; } void cheng(int x,ll y){ if (lazyh[x]){ lazyh[x]=(lazyh[x]*y)%mod; } lazyc[x]=(lazyc[x]*y)%mod; val[x]=(val[x]*y)%mod; sum[x]=(sum[x]*y)%mod; } void pushdown(int x){ if (rev[x]){ rev[x]^=1,swap(son[x][0],son[x][1]); if (son[x][0]) rev[son[x][0]]^=1; if (son[x][1]) rev[son[x][1]]^=1; } if (lazyc[x]!=1){ if (son[x][0]) cheng(son[x][0],lazyc[x]); if (son[x][1]) cheng(son[x][1],lazyc[x]); lazyc[x]=1; } if (lazyh[x]){ if (son[x][0]) jia(son[x][0],lazyh[x]); if (son[x][1]) jia(son[x][1],lazyh[x]); lazyh[x]=0; } } void relax(int x){ if (!isroot(x)) relax(fa[x]); pushdown(x); } void rotata(int x){ int y=fa[x],d=which(x),dd=which(y); if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y]; fa[son[x][d^1]]=y,son[y][d]=son[x][d^1]; fa[y]=x,son[x][d^1]=y; update(y); } void splay(int x){ relax(x); while (!isroot(x)){ if (isroot(fa[x])) rotata(x); else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x); else rotata(x),rotata(x); } update(x); } void access(int x){ for (int p=0;x;x=fa[x]){ splay(x); son[x][1]=p; update(x); p=x; } } void make_root(int x){ access(x); splay(x); rev[x]^=1; } void link(int x,int y){ make_root(x),fa[x]=y; } void cut(int x,int y){ make_root(x); access(y); splay(y); son[y][0]=fa[x]=0; update(y); } void split(int x,int y){ make_root(x); access(y); splay(y); } void add(int x,int y,ll z){ split(x,y); jia(y,z); } void multiply(int x,int y,ll z){ split(x,y); cheng(y,z); } void query(int x,int y){ split(x,y); printf("%u\n",sum[y]%mod); } }lct; int main(){ // freopen("tree.in","r",stdin); // freopen("tree.out","w",stdout); char st[12]; int u,v,U,V; ll UU,VV; memset(size,0,sizeof(size)); memset(fa,0,sizeof(fa)); memset(son,0,sizeof(son)); memset(rev,0,sizeof(rev)); scanf("%d%d",&n,&q); for (int i=1;i<=n;i++){ val[i]=1,sum[i]=1,lazyc[i]=1,lazyh[i]=0,size[i]=1; } for (int i=1;i<n;i++){ scanf("%d%d",&u,&v); lct.link(u,v); } while (q--){ scanf("%s%d%d",st+1,&u,&v); if (st[1]=='+') scanf("%u",&UU),lct.add(u,v,UU); else if (st[1]=='-') scanf("%d%d",&U,&V),lct.cut(u,v),lct.link(U,V); else if (st[1]=='*') scanf("%u",&UU),lct.multiply(u,v,UU); else lct.query(u,v); } return 0; }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2631
做法:链乘链加:先传乘标记,并且把加标记乘上这个数,再传加标记;
看个变形就很显然了:(ax+b)*c=a*c*x+b*c,显然加标记也要乘上这个数。