zoukankan      html  css  js  c++  java
  • 可持久化线段树维护启发式合并的可持久化并查集

    BZOJ 3673: 可持久化并查集

    n个集合 m个操作
    操作:
    1 a b 合并a,b所在集合
    2 k 回到第k次操作之后的状态(查询算作操作)
    3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
    
    0<n,m<=2*10^4
    

    题目链接

    偶然看到这个数据结构,发现挺简单的,前提是会可持久化线段树,可持久化并查集可以说是可持久化线段树的应用。

    并查集维护的是一个父节点指针数组,附带的有时又要维护秩之类的。实习可持久化,我们可以维护多个数组。这样空间肯定是会爆的。那么我们如果直接用主席树维护数组呢。改父亲结点,变成了单点更新。操作回滚变成了普通的主席树回滚。合并,如果不考虑压缩路径直接合并即可。由于主席树中压缩路径不方便回滚(个人感觉)。看了看大牛门的写法,大都是启发式合并,也就是(秩)。到此可持久化线段树可持久化数组可持久化并查集

    看不懂的建议先学个前置技能。并查集的启发式合并,和主席树。

    /**************************************************************
        Problem: 3673
        User: Q1143316492
        Language: C++
        Result: Accepted
        Time:64 ms
        Memory:64576 kb
    ****************************************************************/
     
    /**
     * BZOJ 3673 可持久化线段树 维护启发式合并的可持久化并查集
     */
    //#pragma GCC optimize(2)
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <cstdlib>
    #include <map>
    #include <set>
     
    using namespace std;
    typedef long long LL;
    const int INF = 0x3F3F3F3F;
    const int INT_MAX = 0x7FFFFFFF;
    const LL LLINF = 0x3F3F3F3F3F3F3F3F;
    const double PI = acos(-1);
    const int MAXN = 2e5 + 10;
    const int MAXM = 1e6 + 10;
     
    struct Node {
        int l, r, faz, rank;
    } tree[MAXN * 20];
     
    int n, m, root[MAXN], tot;
     
    int build(int l, int r) {
        int now = ++tot;
        if(l == r) {
            tree[now].faz = l;
            tree[now].rank = 0;
            return now;
        }
        int mid = (l + r) >> 1;
        tree[now].l = build(l, mid);
        tree[now].r = build(mid + 1, r);
        return now;
    }
     
    int query(int rt, int l, int r, int x) {
        if(l == r) {
            return rt;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) {
            return query(tree[rt].l, l, mid, x);
        } else {
            return query(tree[rt].r, mid + 1, r, x);
        }
    }
     
    int find_root(int rt, int x) {
        int y = query(rt, 1, n, x);
        if(x == tree[y].faz) {
            return y;
        }
        return find_root(rt, tree[y].faz);
    }
     
    int update(int rt, int l, int r, int pos, int val) {
        int now = ++tot;
        tree[now] = tree[rt];
        if(l == r) {
            tree[now].faz = val;
            tree[now].rank = tree[rt].rank;
            return now;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) {
            tree[now].l = update(tree[now].l, l, mid, pos, val);
        } else {
            tree[now].r = update(tree[now].r, mid + 1, r, pos, val);
        }
        return now;
    }
     
    void add(int now, int l, int r, int pos) {
        if(l == r) {
            tree[now].rank++;
            return ;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) {
            add(tree[now].l, l, mid, pos);
        } else {
            add(tree[now].r, mid + 1, r, pos);
        }
    }
     
    int main() {
     
        while(~scanf("%d %d", &n, &m)) {
            tot = 0;
            root[0] = build(1, n);
            for(int i = 1; i <= m; i++ ) {
                int opt;
                scanf("%d", &opt);
                if(opt == 1) {
                    int a, b;
                    scanf("%d %d", &a, &b);
                    root[i] = root[i - 1];
                    int x = find_root(root[i], a);
                    int y = find_root(root[i], b);
                    if(tree[x].faz == tree[y].faz) {
                        continue;
                    }
                    if(tree[x].rank > tree[y].rank) {
                        swap(x, y);
                    }
                    root[i] = update(root[i - 1], 1, n, tree[x].faz, tree[y].faz);
                    if(tree[x].rank == tree[y].rank) {
                        add(root[i], 1, n, tree[y].faz);
                    }
                } else if(opt == 2) {
                    int k;
                    scanf("%d", &k);
                    root[i] = root[k];                
                } else if(opt == 3) {
                    int a, b;
                    scanf("%d %d", &a, &b);
                    root[i] = root[i - 1];
                    a = find_root(root[i], a);
                    b = find_root(root[i], b);
                    if(tree[a].faz == tree[b].faz) {
                        puts("1");
                    } else {
                        puts("0");
                    }
                }
            }
        }
     
        return 0;
    }
    
  • 相关阅读:
    EMQ X v4.3 正式发布:性能大幅提升,更好用的多语言扩展
    全新 EMQ X Cloud 物联网云平台重磅发布
    MQTT 和 CoAP 在 EMQ X 世界的一次「约会」
    Python MQTT 异步框架 —— HBMQTT
    EMQ X 团队:连接数亿关键 IoT 设备|EMQ 2021 全球招聘季
    让每一个来自社区的声音被听见、有回响:EMQ X 开源项目正式采用 RFC 流程
    Kuiper 1.1.2 正式发布
    Xamarin.Forms iOS打包上传AppStore,奇妙的崩溃 EXC_CRASH (SIGABRT)
    大数据系列修炼-Scala课程01
    文本摘要简述
  • 原文地址:https://www.cnblogs.com/Q1143316492/p/9309963.html
Copyright © 2011-2022 走看看