[Luogu P3402]可持久化并查集

考虑把并查集放到主席树上维护,达到可以查询过去版本的目的。

由于并查集时间复杂度是基于均摊分析的,所以不能路径压缩。此处可以使用按秩合并或者启发式合并。

所以我们在主席树上维护 \(dep\)\(fa\),表示这个节点的深度和父亲(这里的节点指的是主席树上的节点,父亲指的是这个节点对应实际节点的父亲)。

然后合并的时候把 \(dep\) 小的合并到 \(dep\) 大的节点上,设 \(dep[x]<dep[y]\),即在主席树中使得 \(fa[fa[x]]=fa[y]\) 即可。

按秩合并可能会出现 \(dep[x]=dep[y]\) 的情况,此时我们令 \(dep[y]\) 的深度 \(+1\) 即可。此时我们发现新节点在 \(merge\) 时候已经建过了,所以不用再建一个新版本,减少了空间。

并查集查询只需要查找实际节点对应的主席树节点是哪个即可,然后暴力跳父亲。

代码如下:

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std;
const int N = 200010;
inline int read()
{
    int s = 0, w = 1;
    ri char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();
    return s * w;
}
int n, m, root[N];
struct Tree
{
    int lc, rc, fa, dep;
} D[N * 40];
int cnt;
void Build(int &x, int l, int r)
{
    x = ++cnt;
    if (l == r)
    {
        D[x].fa = l;
        return;
    }
    int mid = (l + r) / 2;
    Build(D[x].lc, l, mid);
    Build(D[x].rc, mid + 1, r);
}
void Merge(int pre, int &x, int l, int r, int px, int py)
{
    x = ++cnt;
    D[x] = D[pre];
    if (l == r)
    {
        D[x].fa = py;
        return;
    }
    int mid = (l + r) / 2;
    if (px <= mid)
        Merge(D[pre].lc, D[x].lc, l, mid, px, py);
    else
        Merge(D[pre].rc, D[x].rc, mid + 1, r, px, py);
}
void UpDate(int x, int l, int r, int pos)
{
    if (l == r)
    {
        D[x].dep++;
        return;
    }
    int mid = (l + r) / 2;
    if (pos <= mid)
        UpDate(D[x].lc, l, mid, pos);
    else
        UpDate(D[x].rc, mid + 1, r, pos);
}
int Ask(int x, int l, int r, int pos)
{
    if (l == r)
        return x;
    int mid = (l + r) / 2;
    if (pos <= mid)
        return Ask(D[x].lc, l, mid, pos);
    return Ask(D[x].rc, mid + 1, r, pos);
}
int Find(int x, int pos)
{
    int id = Ask(x, 1, n, pos);
    if (D[id].fa == pos)
        return id;
    return Find(x, D[id].fa);
}
signed main()
{
    n = read(), m = read();
    Build(root[0], 1, n);
    for (ri int i = 1; i <= m; i++)
    {
        int opt, x, y;
        opt = read(), x = read();
        if (opt == 1)
        {
            root[i] = root[i - 1], y = read();
            int fx = Find(root[i], x), fy = Find(root[i], y);
            if (D[fx].fa == D[fy].fa)
                continue;
            if (D[fx].dep > D[fy].dep)
                swap(fx, fy);
            Merge(root[i - 1], root[i], 1, n, D[fx].fa, D[fy].fa);
            if (D[fx].dep == D[fy].dep)
                UpDate(root[i], 1, n, D[fy].fa);
        }
        else if (opt == 2)
            root[i] = root[x];
        else
        {
            root[i] = root[i - 1], y = read();
            int fx = Find(root[i], x), fy = Find(root[i], y);
            printf("%d\n", (int)(fx == fy));
        }
    }
    return 0;
}
posted @ 2021-02-22 14:29  zkdxl  阅读(53)  评论(1编辑  收藏  举报