zoukankan      html  css  js  c++  java
  • 「luogu3402」【模板】可持久化并查集

    「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;
    }
    
  • 相关阅读:
    快速排序算法
    HTTP中的重定向和请求转发的区别
    单链表的逆置(头插法和就地逆置)
    水仙花数学习
    构建n位元的格雷码
    算法学习day01 栈和队列
    数据结构学习总结 线性表之双向链表
    设计模式
    Nginx 初步认识
    数据结构学习总结(2) 线性表之单链表
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12250151.html
Copyright © 2011-2022 走看看