zoukankan      html  css  js  c++  java
  • P1501 [国家集训队]Tree II

    做法

    P1501 [国家集训队]Tree II

    树上懒惰标记维护动态路径模板题

    做法

    其实做这题也能练一下对(LCT)的了解

    我们对(x,y)这条路径修改时:(Split(x,y);....(y)),传到(y)上去就行了

    我们发现不管什么操作都会用到(Access),其中把底下的点上旋(splay)的同时会把(y)上的标记取下来

    和线段树差不多吧不知道为什么是道黑题

    My complete code

    写代码(15min)+调试(15min)感觉比模板还容易打

    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const LL maxn=1e6,p=51061;
    inline LL Read(){
    	LL x(0),f(1);char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    LL n,m;
    LL val[maxn],sum[maxn],lazya[maxn],lazym[maxn],fa[maxn],son[maxn][2],r[maxn],size[maxn],sta[maxn];
    
    inline bool Notroot(LL x){
    	return (son[fa[x]][0]==x||son[fa[x]][1]==x);
    }
    inline void Pushr(LL x){
    	swap(son[x][0],son[x][1]); r[x]^=1;
    }
    inline void Update(LL x){
    	LL lc(son[x][0]),rc(son[x][1]);
    	sum[x]=(sum[lc]+sum[rc]+val[x])%p,size[x]=size[lc]+size[rc]+1;
    }
    inline void Pusha(LL x,LL w){
    	sum[x]=(sum[x]+size[x]*w%p)%p,val[x]=(val[x]+w)%p,lazya[x]=(lazya[x]+w)%p;
    }
    inline void Pushm(LL x,LL w){
    	sum[x]=sum[x]*w%p,val[x]=val[x]*w%p,lazym[x]=lazym[x]*w%p,lazya[x]=lazya[x]*w%p;
    }
    inline void Pushdown(LL x){
    	LL lc(son[x][0]),rc(son[x][1]);
    	if(lazym[x]!=1){
    		if(lc) Pushm(lc,lazym[x]);
    		if(rc) Pushm(rc,lazym[x]);
    		lazym[x]=1;
    	}
    	if(lazya[x]){
    		if(lc) Pusha(lc,lazya[x]);
    		if(rc) Pusha(rc,lazya[x]);
    		lazya[x]=0;
    	}
    	if(r[x]){
    		if(lc) Pushr(lc);
    		if(rc) Pushr(rc);
    		r[x]=0;
    	}
    }
    inline void Rotate(LL x){
    	LL y(fa[x]),z(fa[y]),lz(son[y][1]==x);
    	if(Notroot(y)) son[z][son[z][1]==y]=x; fa[x]=z;
    	son[y][lz]=son[x][lz^1];
    	if(son[y][lz]) fa[son[y][lz]]=y;
    	son[x][lz^1]=y; fa[y]=x;
    	Update(y),Update(x);
    }
    inline void Splay(LL x){
    	LL y(x),top(0);
    	sta[++top]=y;
    	while(Notroot(y)) sta[++top]=y=fa[y];
    	while(top) Pushdown(sta[top--]);
    	while(Notroot(x)){
    		y=fa[x];
    		if(Notroot(y)){
    			LL z(fa[y]);
    			if(((son[y][1]==x)^(son[z][1]==y))==0) Rotate(y);
    			else Rotate(x);
    		}Rotate(x);
    	}
    }
    inline void Access(LL x){
    	for(LL y=0;x;y=x,x=fa[x]){
    		Splay(x),son[x][1]=y; Update(x);
    	}
    }
    inline void Makeroot(LL x){
    	Access(x),Splay(x),Pushr(x);
    }
    inline void Split(LL x,LL y){
    	Makeroot(x),Access(y),Splay(y);
    }
    inline void Link(LL x,LL y){
    	Makeroot(x),fa[x]=y;
    }
    inline void Delet(LL x,LL y){
    	Split(x,y);
    	fa[x]=son[y][0]=0;
    	Update(y);
    }
    int main(){
    	n=Read(),m=Read();
    	for(LL i=1;i<=n;++i) val[i]=lazym[i]=size[i]=1;
    	for(LL i=1;i<n;++i){
    		LL u(Read()),v(Read());
    		Link(u,v);
    	}
    	while(m--){
    		char ch; scanf(" %c",&ch);
    		if(ch=='+'){
    			LL x(Read()),y(Read()),w(Read());
    			Split(x,y); Pusha(y,w);
    		}else if(ch=='-'){
    			LL x1(Read()),y1(Read()),x2(Read()),y2(Read());
    			Delet(x1,y1),Link(x2,y2);
    		}else if(ch=='*'){
    			LL x(Read()),y(Read()),w(Read());
    			Split(x,y); Pushm(y,w);
    		}else{
    			LL x(Read()),y(Read());
    			Split(x,y);
    			printf("%lld
    ",sum[y]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    第二次作业
    《自动化技术中的进给电气传动》读书笔记1.1-1.2
    证券投资分析
    微信官方文档概述
    联想拯救者Y7000电池无法充电问题
    Ubuntu用户权限管理
    证券市场基础知识
    Markdown All in One使用教程
    Markdown学习笔记
    第九周
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10325330.html
Copyright © 2011-2022 走看看