zoukankan      html  css  js  c++  java
  • P4219 [BJOI2014]大融合

    题目

    P4219 [BJOI2014]大融合

    (LCT)虚边处理模板题

    经过之前做过的(LCT),我们已经对于(LCT)树上动态删(添)边查询链非常熟悉了

    经过以前做的树形动规,显然x与y各自子树乘积(口胡的)

    所以这题需要动态维护子树,(LCT)中我们需要维护虚边,一步一步来分析

    数组(sum_i)(i)(LCT)(多棵(splay)下不分虚实边)里的子树大小,(isum_i)(i)(LCT)中虚儿子的子树和

    先来考虑查询((x,y))(split(x,y),printf("%d ",(isum[x]+1)*(isum[y]+1))),我们拉(x,y)这条链,此时原树子树就是虚边(画个图就懂了吧)

    现在思考什么时候我们需要更新(建议自己(yy)一下,对着函数很好想的),只需要思考几个函数,因为其他的差不多都是调用这几个

    Update

    inline void Update(LL x){
    	sum[x]=sum[son[x][0]]+sum[son[x][1]]+isum[x]+1;
    }
    

    (Splay(x)):反正是单独一棵(splay)上旋不需要管
    (Access(x)):思考拉链的过程中间是变化了很多次虚实边的,一加一减即可

    inline void Access(LL x){
    	for(LL y=0;x;y=x,x=fa[x]){
    	    Splay(x); isum[x]+=sum[son[x][1]];
    		son[x][1]=y; isum[x]-=sum[son[x][1]];
    		Update(x);
    	}
    }
    

    (Link(x,y)):我们平时是(x)变成原根(成为该(splay)深度最小的引边)作为(y)的轻儿子
    但会影响到很多值((y)位于很多结点的下方),如果往上爬会特别麻烦,我们把(y)旋到这(LCT)的根就好了

    inline void Link(LL x,LL y){
    	Makeroot(x),Access(y),Splay(y);
    	fa[x]=y;
    	isum[y]+=sum[x];
        Update(y);
    }
    

    (Delet(x,y)):删的是实边不需要管

    My complete code

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    typedef int LL;
    const LL maxn=1e6;
    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 sum[maxn],isum[maxn],son[maxn][2],fa[maxn],r[maxn],sta[maxn];
    
    inline void Update(LL x){
    	sum[x]=sum[son[x][0]]+sum[son[x][1]]+isum[x]+1;
    }
    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 Pushdown(LL x){
    	if(r[x]){
    		if(son[x][0]) Pushr(son[x][0]);
    		if(son[x][1]) Pushr(son[x][1]);
    		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[z][1]==y)^(son[y][1]==x))) Rotate(y);
    			else Rotate(x);
    		}
    		Rotate(x);
    	}
    }
    inline void Access(LL x){
    	for(LL y=0;x;y=x,x=fa[x]){
    	    Splay(x); isum[x]+=sum[son[x][1]];
    		son[x][1]=y; isum[x]-=sum[son[x][1]];
    		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),Access(y),Splay(y);
    	fa[x]=y;
    	isum[y]+=sum[x];
        Update(y);
    }
    int main(){
    	n=Read(),m=Read();
    	while(m--){
    		char ch; scanf(" %c",&ch);
    		LL x(Read()),y(Read());
    		if(ch=='A'){
    			Link(x,y);
    		}else{
    			Split(x,y);
    			printf("%d
    ",(isum[x]+1)*(isum[y]+1));
    		}
    	}
    }
    
  • 相关阅读:
    oracle 12C linux centos7.5 安装 12C
    FizzBuzz
    批量判断能否telnet登录
    统计所有机器的挂载情况
    ffmpeg windows vs library 下载地址
    需求文档测试
    接口测试分析
    chrome网页截图
    不要为了测试写一个新系统
    C# 判断是否为数字
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10324952.html
Copyright © 2011-2022 走看看