搬运。要开LL,注意两个遗传标记之间影响。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int mod=51061; struct node { int f,c,son[2]; LL d,s,ad,ch; bool fz; }tr[310000]; void add(int x) { if(x==0)return ; tr[x].s=(tr[x].s+tr[x].ad*tr[x].c)%mod; tr[x].d=(tr[x].d+tr[x].ad)%mod; int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].ad=(tr[lc].ad+tr[x].ad)%mod; tr[rc].ad=(tr[rc].ad+tr[x].ad)%mod; tr[x].ad=0; } void mul(int x) { if(x==0)return ; tr[x].s=(tr[x].s*tr[x].ch)%mod; tr[x].d=(tr[x].d*tr[x].ch)%mod; int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].ch=(tr[lc].ch*tr[x].ch)%mod; tr[lc].ad=(tr[lc].ad*tr[x].ch)%mod; tr[rc].ch=(tr[rc].ch*tr[x].ch)%mod; tr[rc].ad=(tr[rc].ad*tr[x].ch)%mod; tr[x].ch=1; } void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; tr[x].c=tr[lc].c+tr[rc].c+1; if(tr[lc].ch!=1)mul(lc); if(tr[rc].ch!=1)mul(rc); if(tr[lc].ad!=0)add(lc); if(tr[rc].ad!=0)add(rc); tr[x].s=(tr[lc].s+tr[rc].s+tr[x].d)%mod; } void reverse(int x) { tr[x].fz=false; swap(tr[x].son[0],tr[x].son[1]); int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].fz=1-tr[lc].fz; tr[rc].fz=1-tr[rc].fz; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int R,r; R=f;r=tr[x].son[w]; tr[R].son[1-w]=r; if(r!=0)tr[r].f=R; R=ff;r=x; if(tr[R].son[0]==f)tr[R].son[0]=r; else if(tr[R].son[1]==f)tr[R].son[1]=r; tr[r].f=R; R=x;r=f; tr[R].son[w]=r; tr[r].f=R; update(f); update(x); } int tmp[310000]; void splay(int x,int rt) { int s=0,i=x; while(tr[i].f!=rt&&(tr[tr[i].f].son[0]==i||tr[tr[i].f].son[1]==i)) { tmp[++s]=i; i=tr[i].f; } tmp[++s]=i; while(s!=0) { i=tmp[s];s--; if(tr[i].fz==true)reverse(i); if(tr[i].ch!=1)mul(i); if(tr[i].ad!=0)add(i); } while(tr[x].f!=rt&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x)) { int f=tr[x].f,ff=tr[f].f; if(ff==rt||(tr[ff].son[0]!=f&&tr[ff].son[1]!=f)) { if(x==tr[f].son[0])rotate(x,1); else rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);} else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);} else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);} else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);} } } } int n; void make_tree() { tr[0].f=0;tr[0].c=0; tr[0].d=0;tr[0].s=0; tr[0].son[0]=tr[0].son[1]=0; tr[0].ad=0;tr[0].ch=1; tr[0].fz=false; for(int i=1;i<=n;i++) { tr[i].f=0;tr[i].c=1; tr[i].d=1;tr[i].s=1; tr[i].son[0]=tr[i].son[1]=0; tr[i].ad=0;tr[i].ch=1; tr[i].fz=false; } } void access(int x) { int y=0; while(x!=0) { splay(x,0); tr[x].son[1]=y; if(y!=0)tr[y].f=x; y=x;x=tr[x].f; } } void makeroot(int x) { access(x);splay(x,0); tr[x].fz=1-tr[x].fz; } void link(int x,int y) { makeroot(x);tr[x].f=y;access(x); } void cut(int x,int y) { makeroot(x); access(y);splay(y,0); tr[tr[y].son[0]].f=0;tr[y].son[0]=0; update(y); } int find_root(int x) { access(x);splay(x,0); while(tr[x].son[0]!=0)x=tr[x].son[0]; return x; } void increase(int x,int y,LL W) { makeroot(x); access(y);splay(y,0); tr[y].ad=(tr[y].ad+W)%mod; } void multiply(int x,int y,LL W) { makeroot(x); access(y);splay(y,0); tr[y].ch=(tr[y].ch*W)%mod; } LL getsum(int x,int y) { makeroot(x); access(y);splay(y,0); update(y);return tr[y].s%mod; } struct edge { int x,y; }e[310000]; char ss[10]; int main() { // freopen("tree.in","r",stdin); // freopen("tree.out","w",stdout); int m,x,y; LL W; scanf("%d%d",&n,&m); for(int i=1;i<n;i++)scanf("%d%d",&e[i].x,&e[i].y); make_tree(); for(int i=1;i<n;i++)link(e[i].x,e[i].y); for(int i=1;i<=m;i++) { scanf("%s",ss+1); if(ss[1]=='+') { scanf("%d%d%lld",&x,&y,&W); increase(x,y,W); } else if(ss[1]=='*') { scanf("%d%d%lld",&x,&y,&W); multiply(x,y,W); } else if(ss[1]=='-') { scanf("%d%d",&x,&y);cut(x,y); scanf("%d%d",&x,&y);link(x,y); } else { scanf("%d%d",&x,&y); printf("%lld ",getsum(x,y)); } } return 0; }