LCT 维护边双 / 点双的模板

\(\text{LCT}\) 维护边双的做法是:加入一条非树边时,将这段树上路径合并为一个点代表这个边双,具体实现用并查集合并点,在 \(\text{Splay}\)\(\text{Access}\) 的过程中对辅助树上父亲做路径压缩。
\(\text{LCT}\) 维护点双的做法是:加入一条非树边时,将这段树上路径全部砍断,新建一个点代表这个点双,将原来那些点向新点连虚边。
实现方法:直接用 \(\text{Splay}\)\(\text{Access}\) 提取路径并且 \(\text{DFS}\) 遍历这个路径就可以了。

代码是维护路径桥与割点的个数。 洛谷链接

#include<bits/stdc++.h>
using namespace std;

const int N = 200005;

int n,q,lst;

struct bcj
{
    int f[N];
    void init()
    {
        for(int i=1; i<=n; i++)
            f[i]=i;
    }
    int find(int x)
    {
        return f[x]==x?x:f[x]=find(f[x]);
    }
}G;

namespace LCT
{
    const int maxn = N;
    int ch[maxn][2],fa[maxn],s[maxn],rev[maxn];
    
    #define lc(x) (ch[x][0])
    #define rc(x) (ch[x][1])
    
    bcj W;
    #define F(x) (W.find(x))
    
    int g(int x)
    {
        return rc(fa[x]) == x;
    }
    
    int nrt(int x)
    {
        return lc(fa[x]) == x || rc(fa[x]) == x;
    }
    
    void pushup(int x)
    {
        s[x] = s[lc(x)] + s[rc(x)] + 1;
    }
    
    void pushdown(int x)
    {
        if(rev[x])
        {
            swap(lc(lc(x)), rc(lc(x)));
            rev[lc(x)] ^= 1;
            swap(lc(rc(x)), rc(rc(x)));
            rev[rc(x)] ^= 1;
            rev[x] ^= 1;
        }
    }
    
    void rot(int x)
    {
        int y = fa[x], v = g(x);
        if(nrt(y))
            ch[fa[y]][g(y)] = x;
        fa[x] = fa[y];
        ch[y][v] = ch[x][!v];
        fa[ch[x][!v]] = y;
        ch[x][!v] = y;
        fa[y] = x;
        pushup(y);
    }
    
    void splay(int x)
    {
        x = F(x);
        int y; vector<int>v;
        for(y = x; nrt(y); y = fa[y] = F(fa[y]))
            v.push_back(y);
        for(pushdown(y); !v.empty(); v.pop_back())
            pushdown(v.back());
        for(y = fa[x]; nrt(x); rot(x), y = fa[x] = F(fa[x]))
            if(nrt(y))
                rot(g(x) ^ g(y) ? x : y);
        pushup(x);
    }
    
    void access(int x)
    {
        x = F(x);
        for(int y = 0; x; y = x, x = fa[x] = F(fa[x]))
        {
            splay(x);
            rc(x) = y;
        }
    }
    
    void makeroot(int x)
    {
        x = F(x);
        access(x);
        splay(x);
        swap(lc(x), rc(x));
        rev[x] ^= 1;
    }
    
    void link(int x, int y)
    {
        x = F(x); y = F(y);
        makeroot(x);
        access(y);
        splay(y);
        fa[x] = y;
    }
    
    void dfs_merge(int x, int root)
    {
        W.f[x] = root;
        if(lc(x)) dfs_merge(lc(x), root), lc(x) = 0;
        if(rc(x)) dfs_merge(rc(x), root), rc(x) = 0;
    }
    
    void zip(int x, int y)
    {
        x = F(x); y = F(y);
        makeroot(x);
        access(y);
        splay(y);
        dfs_merge(y, y);
        pushup(y);
    }
    
    int query(int x, int y)
    {
        x = F(x); y = F(y);
        makeroot(x);
        access(y);
        splay(y);
        return s[y] - 1;
    }
    
    #undef lc
    #undef rc
    #undef F
}

namespace RST
{
    const int maxn = N << 1;
    int cnt,ch[maxn][2],fa[maxn],s[maxn],rev[maxn];
    
    #define lc(x) (ch[x][0])
    #define rc(x) (ch[x][1])
    
    int g(int x)
    {
        return rc(fa[x]) == x;
    }
    
    int nrt(int x)
    {
        return lc(fa[x]) == x || rc(fa[x]) == x;
    }
    
    void pushup(int x)
    {
        s[x] = s[lc(x)] + s[rc(x)] + (x <= n);
    }
    
    void pushdown(int x)
    {
        if(rev[x])
        {
            swap(lc(lc(x)), rc(lc(x)));
            rev[lc(x)] ^= 1;
            swap(lc(rc(x)), rc(rc(x)));
            rev[rc(x)] ^= 1;
            rev[x] ^= 1;
        }
    }
    
    void rot(int x)
    {
        int y = fa[x], v = g(x);
        if(nrt(y))
            ch[fa[y]][g(y)] = x;
        fa[x] = fa[y];
        ch[y][v] = ch[x][!v];
        fa[ch[x][!v]] = y;
        ch[x][!v] = y;
        fa[y] = x;
        pushup(y);
    }
    
    void splay(int x)
    {
        int y; vector<int>v;
        for(y = x; nrt(y); y = fa[y])
            v.push_back(y);
        for(pushdown(y); !v.empty(); v.pop_back())
            pushdown(v.back());
        for(y = fa[x]; nrt(x); rot(x), y = fa[x])
            if(nrt(y))
                rot(g(x) ^ g(y) ? x : y);
        pushup(x);
    }
    
    void access(int x)
    {
        for(int y = 0; x; y = x, x = fa[x])
        {
            splay(x);
            rc(x) = y;
        }
    }
    
    void makeroot(int x)
    {
        access(x);
        splay(x);
        swap(lc(x), rc(x));
        rev[x] ^= 1;
    }
    
    void link(int x, int y)
    {
        makeroot(x);
        access(y);
        splay(y);
        fa[x] = y;
    }
    
    void dfs_merge(int x, int root)
    {
        fa[x] = root;
        if(lc(x)) dfs_merge(lc(x), root), lc(x) = 0;
        if(rc(x)) dfs_merge(rc(x), root), rc(x) = 0;
        pushup(x);
    }
    
    void zip(int x, int y)
    {
        makeroot(x);
        access(y);
        splay(y);
        dfs_merge(y, ++cnt);
        pushup(cnt);
    }
    
    int query(int x, int y)
    {
        makeroot(x);
        access(y);
        splay(y);
        return s[y];
    }
    
    #undef lc
    #undef rc
}

int main()
{
    scanf("%d %d", &n, &q);
    G.init();
    LCT::W.init();
    RST::cnt = n;
    for(int i = 1, opt, x, y; i <= q; i ++)
    {
        scanf("%d %d %d", &opt, &x, &y);
        x = x ^ lst; y = y ^ lst;
        if(opt == 1)
        {
            if(G.find(x) ^ G.find(y))
                LCT::link(x, y), RST::link(x, y), G.f[G.find(x)] = G.find(y);
            else
                LCT::zip(x, y), RST::zip(x, y);
        }
        if(opt == 2)
        {
            if(G.find(x) ^ G.find(y))
                puts("-1");
            else
                printf("%d\n", lst = LCT::query(x, y));
        }
        if(opt == 3)
        {
            if(G.find(x) ^ G.find(y))
                puts("-1");
            else
                printf("%d\n", lst = RST::query(x, y));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/bestwyj/p/11515667.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值