码迷,mamicode.com
首页 > 其他好文 > 详细

BJOI2014 大融合

时间:2020-03-08 17:22:06      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:%s   while   efi   clu   swa   维护   roo   lld   getc   

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\n",1ll*sum[x]*(sum[y]-sum[x]));
        }
    }
    return 0;
}

BJOI2014 大融合

标签:%s   while   efi   clu   swa   维护   roo   lld   getc   

原文地址:https://www.cnblogs.com/lcyfrog/p/12443317.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!