LCT
记一个乘标记和一个加标记来维护。如果打过维护区间乘和加操作的线段树的话这道题就很轻松了,但是LCT因为会动还要维护一个size。其它都是一些细节,如下传乘标记时也要修改加标记,下传加标记时和要乘上size什么的。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
#define V F void
using namespace std;
typedef unsigned int uint;
const uint p=51061;
struct tree{ int to[2],fa,f; uint a,m,x,s,sz; }t[N];
int n,q,stk[N],tp;
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
#define pd(c) (c!='+'&&c!='-'&&c!='*'&&c!='/')
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)&&pd(ch)) ch=readc();
if (!pd(ch)) return ch;
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
V writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
V _write(int x){ writec(x),puts(""); }
#define rt(x) (t[t[x].fa].to[0]!=x&&t[t[x].fa].to[1]!=x)
V pshp(int x){
t[x].sz=t[t[x].to[0]].sz+t[t[x].to[1]].sz+1;
t[x].s=(t[t[x].to[0]].s+t[t[x].to[1]].s+t[x].x)%p;
}
V pshm(int x,uint m){ (t[x].m*=m)%=p,(t[x].a*=m)%=p,(t[x].x*=m)%=p,(t[x].s*=m)%=p; }
V psha(int x,uint a){ (t[x].a+=a)%=p,(t[x].x+=a)%=p,(t[x].s+=t[x].sz*a%p)%=p; }
V pshd(int x){
int &l=t[x].to[0],&r=t[x].to[1]; uint m=t[x].m,a=t[x].a;
if (m!=1) pshm(l,m),pshm(r,m),t[x].m=1;
if (a) psha(l,a),psha(r,a),t[x].a=0;
if (t[x].f) t[x].f^=1,t[l].f^=1,t[r].f^=1,swap(l,r);
}
V rtt(int x){
int y=t[x].fa,z=t[y].fa,l=t[y].to[0]==x;
if (!rt(y)) t[z].to[t[z].to[0]!=y]=x;
t[x].fa=z,t[y].fa=x,t[t[x].to[l]].fa=y;
t[y].to[l^1]=t[x].to[l],t[x].to[l]=y;
pshp(y),pshp(x);
}
V splay(int x){
for (int i=stk[tp=1]=x;!rt(i);i=t[i].fa) stk[++tp]=t[i].fa;
while (tp) pshd(stk[tp--]);
for (int y=t[x].fa,z=t[y].fa;!rt(x);rtt(x),y=t[x].fa,z=t[y].fa)
if (!rt(y)) rtt((t[z].to[0]==y^t[y].to[0]==x)?x:y);
}
V ccss(int x){
for (int i=0;x;i=x,x=t[x].fa)
splay(x),t[x].to[1]=i,pshp(x);
}
V mkrt(int x){ ccss(x),splay(x),t[x].f^=1; }
V sprt(int x,int y){ mkrt(x),ccss(y),splay(y); }
V lnk(int x,int y){ mkrt(x),t[x].fa=y; }
V cut(int x,int y){ sprt(x,y); t[y].to[0]=t[x].fa=0; }
int main(){
n=_read(),q=_read();
for (int i=1;i<=n;i++) t[i].m=t[i].sz=t[i].x=1;
for (int i=1,x,y;i<n;i++)
x=_read(),y=_read(),lnk(x,y);
while (q--){
int f=_read(),x=_read(),y=_read();
switch (f){
case '+': sprt(x,y),psha(y,_read()); break;
case '-': cut(x,y),x=_read(),y=_read(),lnk(x,y); break;
case '*': sprt(x,y),pshm(y,_read()); break;
case '/': sprt(x,y),_write(t[y].s); break;
}
}
return 0;
}