[国家集训队]Tree II

考虑记录如下几个量:
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的感觉就是这样吧。

posted @ 2021-05-10 20:44  fhq_treap  阅读(54)  评论(0编辑  收藏  举报