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

    经典也是最基础的Link Cut Tree维护子树问题。我们考虑维护子树有哪些不同,无非就是需要去维护虚儿子,在这里就是维护虚儿子的size,记为si

    • pushup(x) 这时的更新来源除了左右儿子和自己以外还有虚儿子
    • access(x) 由于access操作是做虚实互换的过程,会对虚儿子数据产生影响
    • link(x,y) 授予了新的父子关系,但这种关系是通过虚儿子实现的

    需要注意 cut(x,y) 本身虽然没有影响虚儿子但也要更新一下

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100005;
    
    int n,m,val[N];
    
    struct LinkCutTree {
        int top, q[N], ch[N][2], fa[N], xr[N], rev[N], s[N], si[N];
        inline void pushup(int x) { // !
            s[x]=s[ch[x][0]]+s[ch[x][1]]+si[x]+1;
        }
        inline void pushdown(int x) {
            if(!rev[x])
                return;
            rev[ch[x][0]]^=1;
            rev[ch[x][1]]^=1;
            rev[x]^=1;
            swap(ch[x][0],ch[x][1]);
        }
        inline bool isroot(int x) {
            return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
        }
        inline void rotate(int p) {
            int q=fa[p], y=fa[q], x=ch[fa[p]][1]==p;
            ch[q][x]=ch[p][x^1];
            fa[ch[q][x]]=q;
            ch[p][x^1]=q;
            fa[q]=p;
            fa[p]=y;
            if(y)
                if(ch[y][0]==q)
                    ch[y][0]=p;
                else  if(ch[y][1]==q)
                    ch[y][1]=p;
            pushup(q);
            pushup(p);
        }
        inline void splay(int x) {
            q[top=1]=x;
            for(int i=x; !isroot(i); i=fa[i])
                q[++top]=fa[i];
            for(int i=top; i; i--)
                pushdown(q[i]);
            for(; !isroot(x); rotate(x))
                if(!isroot(fa[x]))
                    rotate((ch[fa[x]][0]==x)==(ch[fa[fa[x]]][0]==fa[x])?fa[x]:x);
        }
        void access(int x) { // !
            for(int t=0; x; t=x,x=fa[x])
                splay(x),si[x]+=s[ch[x][1]],si[x]-=s[ch[x][1]=t],pushup(x);
        }
        void makeroot(int x) {
            access(x);
            splay(x);
            rev[x]^=1;
        }
        int find(int x) {
            access(x);
            splay(x);
            while(ch[x][0])
                x=ch[x][0];
            return x;
        }
        void split(int x,int y) {
            makeroot(x);
            access(y);
            splay(y);
        }
        void cut(int x,int y) { // !
            split(x,y);
            if(ch[y][0]==x)
                ch[y][0]=0, fa[x]=0;
            pushup(y);
        }
        void link(int x,int y) { // !
            split(x,y);
            si[fa[x]=y]+=s[x];
            pushup(y);
        }
    } T;
    
    int main() {
        ios::sync_with_stdio(false);
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            T.s[i]=1;
        for(int i=1; i<=m; i++) {
            string str;
            cin>>str;
            int u,v;
            cin>>u>>v;
            if(str[0]=='A') {
                T.link(u,v);
            } else {
                T.cut(u,v);
                T.makeroot(u);
                T.makeroot(v);
                cout<<T.s[u]*T.s[v]<<endl;
                T.link(u,v);
            }
        }
    }
    
    
  • 相关阅读:
    July 08th. 2018, Week 28th. Sunday
    July 07th. 2018, Week 27th. Saturday
    兄弟组件bus传值
    vue 父子组件传值
    路由传值的三种方式
    jQuery 操作表格
    原生js实现开关功能
    跨域解决方法
    正则判断密码难度
    cookie封装函数
  • 原文地址:https://www.cnblogs.com/mollnn/p/11704915.html
Copyright © 2011-2022 走看看