zoukankan      html  css  js  c++  java
  • 【洛谷P4219】 [BJOI2014]大融合【LCT】

    传送门

    Solution

    首先边((x,y))的负载显然可以转化为,(x,y)所在树中,((x)的子树大小(-y)的子树大小)(*y)的子树大小(假设(x)(y)的父亲)

    我们想用(LCT)来维护这样的东西,但之前我们提到过,(LCT)维护子树信息十分困难,但子树和这样的也是比较好处理的:

    显然子树和可以由实子树和和虚子树和组成,于是考虑用(sum1)维护子树和,(sum2)维护虚子树和,那么(pushup)就很好写了:

    inline void pushup(int x){
    	sum1[x]=sum1[ch[x][0]]+sum1[ch[x][1]]+1+sum2[x];
    }
    

    接下来考虑我们什么时候改变了(sum2),其实只有两个地方:

    (1.access)

    (access)过程中,我们将每个点(x)的右儿子改变,(sum2)自然就会增加原来右儿子的子树和,减去新的右儿子的子树和:

    inline void access(int x){
    	for(int last=0;x;last=x,x=fa[x]){
    		Splay(x);
    		sum2[x]+=sum1[ch[x][1]];
    		sum2[x]-=sum1[last];
    		ch[x][1]=last;
    		pushup(x);
    	}
    }
    

    (2.link)

    (link)过程中,我们在((x,y))间连了一条轻边,于是要在(y)(sum2)中增加(x)所在树的点权和:

    inline void link(int x,int y){
    	split(x,y); //split其实就是完成了正常link的makeroot操作并且将x到y的链找出来
    	sum2[y]+=sum1[x]; 
    	fa[x]=y;
    }
    

    其它的就是模板了.

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+10;
    int n,sum1[N],ch[N][2],fa[N],rev[N],sum2[N];//sum1为所有子树siz之和,sum2为虚子树siz之和 
    inline bool which(int x){return ch[fa[x]][1]==x;}
    inline void pushup(int x){
    	sum1[x]=sum1[ch[x][0]]+sum1[ch[x][1]]+1+sum2[x];
    }
    inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    inline void rever(int x){
    	swap(ch[x][0],ch[x][1]);
    	rev[x]^=1;
    }
    inline void pushdown(int x){
    	if(!rev[x]) return ;
    	if(ch[x][0]) rever(ch[x][0]);
    	if(ch[x][1]) rever(ch[x][1]);
    	rev[x]=0;
    }
    inline void Rotate(int x){
    	int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
    	if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
    	ch[y][wx]=ch[x][wx^1];
    	if(ch[y][wx]) fa[ch[y][wx]]=y;
    	ch[x][wx^1]=y;fa[y]=x;
    	pushup(y);
    }
    int stk[N],top;
    inline void Splay(int x){
    	int now=x;
    	stk[top=1]=now;
    	while(!isroot(now)) now=fa[now],stk[++top]=now;
    	while(top) pushdown(stk[top--]);
    	while(!isroot(x)){
    		int y=fa[x];
    		if(!isroot(y)){
    			if(which(x)==which(y)) Rotate(y);
    			else Rotate(x);
    		}Rotate(x);
    	}
    	pushup(x); 
    } 
    inline void access(int x){
    	for(int last=0;x;last=x,x=fa[x]){
    		Splay(x);
    		sum2[x]+=sum1[ch[x][1]];
    		sum2[x]-=sum1[last];
    		ch[x][1]=last;
    		pushup(x);
    	}
    }
    inline void makeroot(int x){
    	access(x);Splay(x);
    	rever(x);
    }
    inline void split(int x,int y){
    	makeroot(x);
    	access(y);Splay(y);
    }
    inline void link(int x,int y){
    	split(x,y); 
    	sum2[y]+=sum1[x]; 
    	fa[x]=y;
    }
    int q;
    char op[10];
    int main(){
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<=n;++i) sum1[i]=1;
    	while(q--){
    		int x,y;
    		scanf("%s%d%d",op,&x,&y);
    		if(op[0]=='A') link(x,y);
    		else makeroot(y),access(x),Splay(y),printf("%lld
    ",1ll*(sum1[y]-sum1[x])*(sum1[x]));	
    	}
    	return 0;
    }
    
  • 相关阅读:
    oracle 查詢表字段明細、字段注釋、表註釋
    Linux Oracle服务启动&停止脚本与开机自启动
    Tomcat7中配置Oracle 11g数据库DBCP连接池
    使用 Tomcat 7 新的连接池 —— Tomcat jdbc pool
    【转】Linux下常用压缩 解压命令和压缩比率对比
    【转】HttpClient容易忽视的细节——连接关闭
    JAVA实现图片验证码
    Flyme密码验证策略升级,忘记锁屏密码及「关机密码」功能
    【转】SpringBoot自定义序列化的使用方式--WebMvcConfigurationSupport
    inux中查看各文件夹大小命令:du -h --max-depth=1
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14243346.html
Copyright © 2011-2022 走看看