考虑记录如下几个量:
v : 每个点的权值
siz : splay中子树大小
s : splay中子树的权值和
lm,la : 两个标记
然后维护操作就行。
[国家集训队]Tree II
#include<iostream>
#include<cstdio>
#define ll long long
#define mod 51061
#define N 100009
ll n,q,f[N],c[N][2],v[N],s[N],siz[N],lm[N],la[N],st[N];
bool r[N];
#define l(x) c[x][0]
#define r(x) c[x][1]
#define mul(x) x = (x * c) % mod
#define add(x,y) x = (x + y) % mod
inline bool nroot(int x){return l(f[x]) == x || r(f[x]) == x;}
inline void up(int x){s[x] = (s[l(x)] + s[r(x)] + v[x]) % mod;siz[x] = (siz[l(x)] + siz[r(x)] + 1);}
inline void pushr(int x){std::swap(l(x),r(x));r[x] ^= 1;}
inline void pushm(int x,int c){mul(s[x]),mul(v[x]),mul(lm[x]),mul(la[x]);}
inline void pusha(int x,int c){add(s[x],c * siz[x]),add(v[x],c),add(la[x],c);}
inline void pushdown(int x){
if(lm[x] != 1)pushm(l(x),lm[x]),pushm(r(x),lm[x]),lm[x] = 1;
if(la[x])pusha(l(x),la[x]),pusha(r(x),la[x]),la[x] = 0;
if(r[x]){
if(l(x))pushr(l(x));
if(r(x))pushr(r(x));
r[x] = 0;
}
}
inline void rotate(int x){
int y = f[x],z = f[y],k = r(y) == x,w = c[x][!k];
if(nroot(y))c[z][r(z) == y] = x;c[x][!k] = y;c[y][k] = w;
if(w)f[w] = y;f[y] = x;f[x] = z;
up(y),up(x);
}
inline void splay(int x){
int y = x,z = 0;
st[++z] = y;
while(nroot(y))st[++z] = y = f[y];
while(z)pushdown(st[z -- ]);
while(nroot(x)){
y = f[x],z = f[y];
if(nroot(y))
rotate((l(y) == x) ^ (l(z) == y) ? x : y);
rotate(x);
}
up(x);
}
inline void access(int x){
for(int y = 0;x;x = f[y = x])
splay(x),r(x) = y,up(x);
}
inline void makeroot(int x){access(x),splay(x),pushr(x);}
inline void split(int x,int y){makeroot(x),access(y),splay(y);}
inline void link(int x,int y){makeroot(x);f[x] = y;}
inline void cut(int x,int y){split(x,y);f[x] = l(y) = 0;}
int main(){
scanf("%lld%lld",&n,&q);
for(int i = 1;i <= n;++i)
v[i] = 1,siz[i] = 1,lm[i] = 1;
for(int i = 1;i <= n - 1;++i){
ll x,y;
scanf("%lld%lld",&x,&y);
link(x,y);
}
while(q -- ){
char a;
while(a != '*' && a != '/' && a != '+' && a != '-')
a = getchar();
switch(a){
case '+':{
ll x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
split(x,y),pusha(y,k);
break;
}
case '-':{
ll x,y;
scanf("%lld%lld",&x,&y);
cut(x,y);
scanf("%lld%lld",&x,&y);
link(x,y);
break;
}
case '*':{
ll x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
split(x,y),pushm(y,k);
break;
}
case '/':{
ll x,y;
scanf("%lld%lld",&x,&y);
split(x,y);
std::cout<<s[y]<<std::endl;
break;
}
}
a = 'q';
}
}
或许写完一遍就A的感觉就是这样吧。