suxxsfe

一言(ヒトコト)

P1501 [国家集训队]Tree II

https://www.luogu.com.cn/problem/P1501

给定 \(n\) 个节点的树,每个操作是路径的点权都加一个数,路径点权都乘一个数,查询路径点权和(对 \(51061\) 取模),断一条边并加入一条新边(保证合法)

就是用 lct 维护,打反转(换根用)、加法、乘法的懒标记,pushdown 时,还要用到子树大小
其实就和那个线段树模板二一样,因为优先级,乘法标记下传时,子树的加法标记、乘法标记、权值、结果(就是当前的和),都要乘它的乘法标记
而下传加法时,就是让子树的加法标记、结果都加上这个加法标记乘以对应的子树大小,而子树权值就只加它的加法标记就行了

注意模数的平方超过了 int 范围,要开 long long

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define mod 51061
#define N 100005
struct LCT{
	struct tr{
		tr *son[2],*fa;
		LL add,mul;
		LL res,val,size;
		int tag;
	}*null,*pos[N],dizhi[N];
	#define ident(tree,fa) (fa->son[1]==tree)
	#define notroot(tree) (tree->fa->son[0]==tree||tree->fa->son[1]==tree)
	inline void pushup(tr *tree){
		tree->res=(tree->son[0]->res+tree->son[1]->res+tree->val)%mod;
		tree->size=tree->son[0]->size+tree->son[1]->size+1;
	}
	inline void connect(tr *tree,tr *fa,int k){fa->son[k]=tree;tree->fa=fa;}
	inline void pushdown(tr *tree){
		reg LL tmp;
		if(tree->tag){
			std::swap(tree->son[0]->son[0],tree->son[0]->son[1]);
			std::swap(tree->son[1]->son[0],tree->son[1]->son[1]);
			tree->son[0]->tag^=1;tree->son[1]->tag^=1;
			tree->tag=0;
		}
		if(tree->mul!=1){
			tmp=tree->mul;
			tree->son[0]->add*=tmp;tree->son[1]->add*=tmp;
			tree->son[0]->add%=mod;tree->son[1]->add%=mod;
			tree->son[0]->mul*=tmp;tree->son[1]->mul*=tmp;
			tree->son[0]->mul%=mod;tree->son[1]->mul%=mod;
			tree->son[0]->val*=tmp;tree->son[1]->val*=tmp;
			tree->son[0]->val%=mod;tree->son[1]->val%=mod;
			tree->son[0]->res*=tmp;tree->son[1]->res*=tmp;
			tree->son[0]->res%=mod;tree->son[1]->res%=mod;
			tree->mul=1;
		}
		if(tree->add){
			tmp=tree->add;
			tree->son[0]->add+=tmp;tree->son[1]->add+=tmp;
			tree->son[0]->add%=mod;tree->son[1]->add%=mod;
			tree->son[0]->val+=tmp;tree->son[1]->val+=tmp;
			tree->son[0]->val%=mod;tree->son[1]->val%=mod;
			tree->son[0]->res+=tmp*tree->son[0]->size;tree->son[1]->res+=tmp*tree->son[1]->size;
			tree->son[0]->res%=mod;tree->son[1]->res%=mod;
			tree->add=0;
		}
	}
	inline void rotate(tr *tree){
		tr *fa=tree->fa,*faa=fa->fa;
		pushdown(fa);pushdown(tree);
		int k=ident(tree,fa);
		connect(tree->son[k^1],fa,k);
		tree->fa=faa;
		if(notroot(fa)) faa->son[ident(fa,faa)]=tree;
		connect(fa,tree,k^1);
		pushup(fa);pushup(tree);
	}
	inline void splay(reg tr *x){
		reg tr *fa,*faa;
		while(notroot(x)){
			fa=x->fa;faa=fa->fa;
			if(notroot(fa)) ident(fa,faa)^ident(x,fa)?rotate(x):rotate(fa);
			rotate(x);
		}
	}
	inline void access(tr *x){
		for(reg tr *lastx=null;x!=null;lastx=x,x=x->fa){
			pushdown(x);
			splay(x);
			x->son[1]=lastx;pushup(x);
		}
	}
	inline void makeroot(tr *x){
		access(x);splay(x);
		x->tag^=1;std::swap(x->son[0],x->son[1]);
	}
	inline tr *findroot(tr *x){
		access(x);splay(x);
		while(x->son[0]!=null) pushdown(x),x=x->son[0];
		splay(x);
		return x;
	}
	inline void link(tr *x,tr *y){
		makeroot(x);
		if(findroot(y)!=x) x->fa=y;
	}
	inline void cut(tr *x,tr *y){
		makeroot(x);
		if(findroot(y)!=x||y->fa!=x||y->son[0]!=null) return;
		y->fa=x->son[1]=null;
		pushup(x);
	}
	inline void split(tr *x,tr *y){
		makeroot(x);
		access(y);splay(y);
	}
	inline void init(int n){
		null=&dizhi[0];
		for(reg int i=1;i<=n;i++){
			pos[i]=&dizhi[i];
			dizhi[i].son[0]=dizhi[i].son[1]=null;
			dizhi[i].val=dizhi[i].res=1;
			dizhi[i].size=dizhi[i].mul=1;
			dizhi[i].fa=null;
		}
	}
}lct;
int main(){
//		std::freopen("P1501_2.in","r",stdin);
	int n=read(),q=read();
	lct.init(n);
	int a,b,c,d;
	while(--n){
		a=read();b=read();
		lct.link(lct.pos[a],lct.pos[b]);
	}
	reg char op;
	LCT::tr *tree;
	while(q--){
		op=getchar();
		while(op!='+'&&op!='-'&&op!='/'&&op!='*') op=getchar();
		a=read();b=read();
		if(op=='+'){
			c=read();
			lct.split(lct.pos[a],lct.pos[b]);
			tree=lct.pos[b];
			tree->add+=c;tree->val+=c;tree->res+=c*tree->size;
			tree->add%=mod;tree->val%=mod;tree->res%=mod;
		}
		else if(op=='-'){
			c=read();d=read();
			lct.cut(lct.pos[a],lct.pos[b]);
			lct.link(lct.pos[c],lct.pos[d]);
		}
		else if(op=='*'){
			c=read();
			lct.split(lct.pos[a],lct.pos[b]);
			tree=lct.pos[b];
			tree->add*=c;tree->mul*=c;tree->val*=c;tree->res*=c;
			tree->add%=mod;tree->mul%=mod;tree->val%=mod;tree->res%=mod;
		}
		else{
			lct.split(lct.pos[a],lct.pos[b]);
			printf("%lld\n",lct.pos[b]->res);
		}
	}
	return 0;
}
posted @ 2020-08-10 11:20  suxxsfe  阅读(128)  评论(0编辑  收藏  举报