• BJOI2014 大融合


    BJOI2014 大融合

    LCT维护子树

    这题要维护的是子树的大小,动态加边,用LCT维护

    (sz_i) 表示虚儿子的大小之和,(sum_i) 表示子树大小

    考虑(sz)什么时候会变

    1. access中,只有一个儿子由虚变实,有一个儿子由实变虚,加减一下就好了

    2. link之后连了虚儿子,需要更新,注意这个时候两个点都必须是根,不然要往上pushup

    另外pushup也要改一下

    #include<iostream> 
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<bitset>
    #include<set>
    #define ls ch[x][0]
    #define rs ch[x][1] 
    using namespace std;
    inline int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    }
    const int N = 100201;
    int ch[N][2],fa[N],sum[N],r[N],sz[N];
    char s[2];
    int nroot(int x){return ch[fa[x]][1]==x||ch[fa[x]][0]==x;}
    void push_up(int x){sum[x]=sum[ls]+sum[rs]+sz[x]+1;}
    void pushr(int x){swap(ls,rs);r[x]^=1;}
    void push_down(int x){if(r[x]){if(ls)pushr(ls); if(rs)pushr(rs); r[x]=0; }}
    void push(int x){if(nroot(x)) push(fa[x]);push_down(x);} 
    int get(int x){return ch[fa[x]][1]==x;}
    void rotate(int x){
    	int f=fa[x],g=fa[f],kx=get(x),kf=get(f);
    	if(nroot(f)) ch[g][kf]=x;fa[x]=g;
    	ch[f][kx]=ch[x][kx^1];fa[ch[x][kx^1]]=f;
    	ch[x][kx^1]=f;fa[f]=x;
    	push_up(f);push_up(x);
    }
    void splay(int x){
    	push(x);
    	while(nroot(x)){
    		int f=fa[x];
    		if(nroot(f)) rotate(get(x)==get(f)?f:x);
    		rotate(x);
    	}
    }
    void access(int x){
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);sz[x]+=sum[rs]-sum[y];rs=y;push_up(x);
    	}
    }
    void makeroot(int x){access(x);splay(x);pushr(x);}
    int findroot(int x){
    	access(x);splay(x);while(ch[x][0]) x=ch[x][0];splay(x);return x;
    }
    void link(int x,int y){
    	makeroot(x);
    	if(findroot(y)!=x){
    		makeroot(y);
    		fa[x]=y;sz[y]+=sum[x];push_up(y);
    	}
    }
    void split(int x,int y){
    	makeroot(x);access(y);splay(y);
    }
    int main(){
    	int n=read(),q=read();
    	for(int i=1;i<=n;i++) sum[i]=1;
    	for(int i=1;i<=q;i++){
    		scanf("%s",s);
    		if(s[0]=='A'){
    			int x=read(),y=read();link(x,y);
    		}else{
    			int x=read(),y=read();
    			split(x,y);
    			printf("%lld
    ",1ll*sum[x]*(sum[y]-sum[x]));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    7-10 社交网络图中结点的“重要性”计算(30 point(s)) 【并查集+BFS】
    7-5 打印选课学生名单(25 point(s)) 【排序】
    7-3 堆栈模拟队列(25 point(s)) 【数据结构】
    7-5 家谱处理(30 分) 【数据结构】
    7-7 最强素数(100 分) 【前缀和】
    PAT 天梯赛 L2-022. 重排链表 【数据结构】
    7-1 列出叶结点(25 分) 【数据结构】
    7-6 公路村村通(30 分) 【prime】
    PAT 甲级 1116. Come on! Let's C (20) 【循环判断】
    PAT 甲级 1104. Sum of Number Segments (20) 【数学】
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/12443317.html
Copyright © 2020-2023  润新知