zoukankan      html  css  js  c++  java
  • 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
    ",lct.pos[b]->res);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    STM32的低功耗模式
    C语言的面向对象技术
    SDIO学习
    读十倍效率开发者有感
    三极管
    压敏电阻
    freertos之任务
    tsar采集数据原理
    NTP学习路线
    使用awk提取字符串中的数字或字母
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13468697.html
Copyright © 2011-2022 走看看