可持久化并查集

因为NOI2018D1T1似乎还有可持久化并查集解法 所以去学了一学

调了我好久 结果是数组开小了 n m 不同阶的出题人都是耍流氓!!!

好现在步入正题 我们对于并查集实际上维护的是一个可以单点修改和查询的数组
如果要支持可持久化的话 我们可以考虑用可持久化线段树来维护这个数组
因为每次修改不超过 l o g ( n ) 个节点 那么我们就可以对于并查集按照启发式合并
时间复杂度 O ( M l o g 2 n ) 空间复杂度 O ( M l o g n )
然后再讲下启发式合并 在两个并查集合并的过程中 每次我们把子树深度小的往子树深度大的集合中合并 那么可以证明复杂度是 O ( l o g n ) 级别的 那么就可以不用路径压缩失去一些信息了

模板

/**************************************************************
    Problem: 3674
    User: lunch
    Language: C++
    Result: Accepted
    Time:1340 ms
    Memory:189584 kb
****************************************************************/

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)

using namespace std;

const int maxn = 2e5 + 10;
int root[maxn], n, m, now, lastans;

namespace Chairman_Tree
{
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
    int cnt;
    struct node
    {
        int ch[2], fa, height;
    }T[maxn * 60];
    void build(int &x, int l, int r)
    {
        x = ++ cnt;
        if(l == r)
            T[x].fa = l;
        else
        {
            build(ls(x), l, mid);
            build(rs(x), mid + 1, r);
        }
    }
    int query(int x, int l, int r, int p)
    {
        if(l == r)
            return x;
        if(p <= mid)
            return query(ls(x), l, mid, p);
        return query(rs(x), mid + 1, r, p);
    }
    void update(int &x, int pre, int l, int r, int p, int dad)
    {
        T[x = ++ cnt] = T[pre];
        if(l == r)
            T[x].fa = dad;
        else
        {
            if(p <= mid)
                update(ls(x), ls(pre), l, mid, p, dad);
            else
                update(rs(x), rs(pre), mid + 1, r, p, dad);
        }
    }
    void add(int &x, int pre, int l, int r, int p)
    {
        T[x = ++ cnt] = T[pre];
        if(l == r)
            ++ T[x].height;
        else
        {
            if(p <= mid)
                add(ls(x), ls(pre), l, mid, p);
            else
                add(rs(x), rs(pre), mid + 1, r, p);
        }
    }
    int find(int x)
    {
        int dad = query(now, 1, n, x);
        while(T[dad].fa != x)
        {
            x = T[dad].fa;
            dad = query(now, 1, n, x);
        }
        return dad;
    }
}

using namespace Chairman_Tree;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("3674.in", "r", stdin);
    freopen("3674.out", "w", stdout);
#endif
    int x, y, z;
    scanf("%d%d", &n, &m);
    build(root[0], 1, n);
    now = root[0];
    For(i, 1, m)
    {
        scanf("%d%d", &x, &y);
        y ^= lastans;
        if(x == 2)
            now = root[y];
        else
            scanf("%d", &z);
        z ^= lastans;
        if(x == 1)
        {
            int u = find(y), v = find(z);
            if(T[u].fa != T[v].fa)
            {
                if(T[u].height > T[v].height)
                    update(now, now, 1, n, T[v].fa, T[u].fa);
                else
                {
                    update(now, now, 1, n, T[u].fa, T[v].fa);
                    if(T[u].height == T[v].height)
                        add(now, now, 1, n, T[v].fa);
                }
            }
        }
        if(x == 3)
            printf("%d\n", lastans = (T[find(y)].fa == T[find(z)].fa ? 1 : 0));
        root[i] = now;      
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81139441
今日推荐