「luogu3402」【模板】可持久化并查集

那年仲夏 提交于 2020-02-01 22:47:32

「luogu3402」【模板】可持久化并查集

传送门
我们可以用一个可持久化数组来存每个节点的父亲。
单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞。
然后考虑如何合并两个点。
由于我们要做到可持久化,所以我们就考虑用启发式合并。
至于路径压缩,ta好像会因为某些原因而MLE和TLE 其实我也没试过
那么我们在合并的时候就只需要借助主席树完成单点查询和修改就好了。
注意一个地方值得注意,就是在修改时因为我们的线段树是可持久化的,所以会通向之前版本的节点,所以不要覆盖之前的信息,不然就不是可持久化了。
参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 2e5 + 5;

int n, m, tot, rt[_];
struct node { int fa, siz; } ;
struct chairmantree { int lc, rc; node u; } t[_ << 5];

inline void build(int& p, int l = 1, int r = n) {
    p = ++tot;
    if (l == r) { t[p].u = (node) { l, 1 }; return ; }
    int mid = (l + r) >> 1;
    build(t[p].lc, l, mid), build(t[p].rc, mid + 1, r);
}

inline void update(int& p, int q, int x, int fa, int siz, int l = 1, int r = n) {
    t[p = ++tot] = t[q];
    if (l == r) { t[p].u = (node) { fa ? fa : t[p].u.fa, siz ? siz : t[p].u.siz }; return ; }
    int mid = (l + r) >> 1;
    if (x <= mid) update(t[p].lc, t[q].lc, x, fa, siz, l, mid);
    else update(t[p].rc, t[q].rc, x, fa, siz, mid + 1, r);
}

inline node query(int p, int x, int l = 1, int r = n) {
    if (l == r) return t[p].u;
    int mid = (l + r) >> 1;
    if (x <= mid) return query(t[p].lc, x, l, mid);
    else return query(t[p].rc, x, mid + 1, r);
}

inline node Find(int p, int x) {
    node Fa = query(rt[p], x);
    if (Fa.fa == x) return Fa; else return Find(p, Fa.fa);
}

inline void merge(int p, int x, int y) {
    node fx = Find(p, x), fy = Find(p, y);
    if (fx.siz < fy.siz) swap(fx, fy);
    update(rt[p], rt[p], fx.fa, 0, fx.siz + fy.siz);
    update(rt[p], rt[p], fy.fa, fx.fa, 0);
}

int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(m), build(rt[0]);
    for (rg int opt, x, y, i = 1; i <= m; ++i) {
        read(opt);
        if (opt == 1) read(x), read(y), rt[i] = rt[i - 1], merge(i, x, y);
        if (opt == 2) read(x), rt[i] = rt[x];
        if (opt == 3) read(x), read(y), rt[i] = rt[i - 1], puts(Find(i, x).fa == Find(i, y).fa ? "1" : "0");
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!