Luogu 3402 可持久化并查集

点开这题纯属无聊……不过既然写掉了,那就丢一个模板好了

不得不说,可持久化并查集实现真的很暴力,就是把并查集的数组弄一个主席树可持久化。

有一点要注意的是不能写路径压缩,这样跳版本的时候会错,所以弄一个按秩合并来降低时间复杂度。

总时间复杂度$O(nlog^2n)$。

听说用siz实现按秩合并会比较好,因为这样还能查询集合大小,有时间以后补上。

Code:

#include <cstdio>
using namespace std;

const int N = 1e5 + 5;
const int M = 2e5 + 5;

int n, qn;

inline void read(int &X) {
    X = 0;
    char ch = 0;
    int op = 1;
    for(; ch > '9'|| ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

struct Node {
    int lc, rc, dep, fa;
};

namespace PUfs {
    Node s[N * 120];
    int root[M * 2], nodeCnt;

    #define mid ((l + r) >> 1)  

    void build(int &p, int l, int r) {
        p = ++nodeCnt;
        if(l == r) {
            s[p].fa = l;
            return;
        }

        build(s[p].lc, l, mid);
        build(s[p].rc, mid + 1, r);
    }

    void modify(int &p, int l, int r, int x, int f, int pre) {
        p = ++nodeCnt;
        if(l == r) {
            s[p].fa = f;
            s[p].dep = s[pre].dep;
            return;
        }
        
        s[p].lc = s[pre].lc, s[p].rc = s[pre].rc;
        if(x <= mid) modify(s[p].lc, l, mid, x, f, s[pre].lc);
        else modify(s[p].rc, mid + 1, r, x, f, s[pre].rc);
    }

    void add(int p, int l, int r, int x) {
        if(l == r) {
            s[p].dep++;
            return;
        }
        if(x <= mid) add(s[p].lc, l, mid, x);
        else add(s[p].rc, mid + 1, r, x);
    }

    int query(int p, int l, int r, int x) {
        if(l == r) return p;

        if(x <= mid) return query(s[p].lc, l, mid, x);
        else return query(s[p].rc, mid + 1, r, x);
    }

    int find(int now, int x) {
        int f = query(now, 1, n, x);
        if(s[f].fa == x) return f;
        return find(now, s[f].fa);
    } 

} using namespace PUfs;

inline void print(int p) {
    printf("%d: ", p);
    for(int j = 1; j <= n; j++)
        printf("%d ", s[find(root[p], j)].fa);  
/*    for(int j = 1; j <= n; j++)
        printf("%d ", query(root[p], 1, n, j));  */
    printf("\n");
}   

inline void swap(int &x, int &y) {
    int t = x;
    x = y;
    y = t;
}

int main() {
    read(n), read(qn);

    nodeCnt = 0;
    build(root[0], 1, n);

//      print(0);

    for(int op, i = 1; i <= qn; i++) {
        read(op);
        if(op == 1) {
            root[i] = root[i - 1];
            int x, y;
            read(x), read(y);
            int fx = find(root[i], x), fy = find(root[i], y);
            if(s[fx].fa == s[fy].fa) continue;
            if(s[fx].dep > s[fy].dep) swap(fx, fy);
            modify(root[i], 1, n, s[fx].fa, s[fy].fa, root[i - 1]);
            if(s[fx].dep == s[fy].dep) add(root[i], 1, n, s[fy].fa);
        }
        if(op == 2) {
            int k;
            read(k);
            root[i] = root[k];
        } 
        if(op == 3) {
            root[i] = root[i - 1];
            int x, y;
            read(x), read(y);
            int fx = find(root[i], x), fy = find(root[i], y);
            if(s[fx].fa == s[fy].fa) puts("1");
            else puts("0");
        }
//      print(i);
    }

    return 0;
}
View Code

 

posted @ 2018-08-14 21:43  CzxingcHen  阅读(162)  评论(0编辑  收藏  举报