zoukankan      html  css  js  c++  java
  • 洛谷P3402 可持久化并查集 题解

    题目链接:https://www.luogu.com.cn/problem/P3402

    题目大意:

    给定 (n) 个集合,第 (i) 个集合内初始状态下只有一个数,为 (i)

    (m) 次操作。操作分为 (3) 种:

    • 1 a b 合并 (a,b) 所在集合;

    • 2 k 回到第 (k) 次操作(执行三种操作中的任意一种都记为一次操作)之后的状态;

    • 3 a b 询问 (a,b) 是否属于同一集合,如果是则输出 (1) ,否则输出 (0)

    解题思路:

    可持久化并查集。并查集 按秩合并,不要路径压缩。

    示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    struct Tree {
        int l, r,val;
    } tree[maxn*80];
    int tot, rootfa[maxn*2], rootdep[maxn*2];
    int n, m;
    void build(int l, int r, int& rt) {
        rt = ++tot;
        if (l == r) {
            tree[rt].val = l;
            return;
        }
        int mid = (l + r) / 2;
        build(l, mid, tree[rt].l);
        build(mid+1, r, tree[rt].r);
    }
    void update(int p, int val, int l, int r, int pt, int &rt) {
        tree[rt = ++tot] = tree[pt];
        if (l == r) {
            tree[rt].val = val;
            return;
        }
        int mid = (l + r) / 2;
        if (p <= mid)
            update(p, val, l, mid, tree[pt].l, tree[rt].l);
        else
            update(p, val, mid+1, r, tree[pt].r, tree[rt].r);
    }
    int query(int p, int l, int r, int rt) {
        if (l == r) return tree[rt].val;
        int mid = (l + r) / 2;
        if (p <= mid)
            return query(p, l, mid, tree[rt].l);
        else
            return query(p, mid+1, r, tree[rt].r);
    }
    int ffind(int ver, int x) {
        int fa = query(x, 1, n, rootfa[ver]);
        return fa == x ? x : ffind(ver, fa);
    }
    void funion(int ver, int x, int y) {
        x = ffind(ver-1, x);
        y = ffind(ver-1, y);
        if (x == y) {
            rootfa[ver] = rootfa[ver-1];
            rootdep[ver] = rootdep[ver-1];
        }
        else {
            int depx = query(x, 1, n, rootdep[ver-1]);
            int depy = query(y, 1, n, rootdep[ver-1]);
            if (depx > depy) swap(x, y);
            update(x, y, 1, n, rootfa[ver-1], rootfa[ver]);
            if (depx == depy) {
                update(y, depy+1, 1, n, rootdep[ver-1], rootdep[ver]);
            }
            else {
                rootdep[ver] = rootdep[ver-1];
            }
        }
    }
    int main() {
        ios::sync_with_stdio(0);
        cin >> n >> m;
        build(1, n, rootfa[0]);
        for (int i = 1; i <= m; i ++) {
            int op, k, a, b;
            cin >> op;
            if (op == 2) cin >> k;
            else cin >> a >> b;
            if (op == 1) {  // 合并a,b所在集合
                funion(i, a, b);
            }
            else if (op == 2) { // 回到第k次操作
                rootfa[i] = rootfa[k];
                rootdep[i] = rootdep[k];
            }
            else {  // 询问a,b是否属于同一集合
                rootfa[i] = rootfa[i-1];
                rootdep[i] = rootdep[i-1];
                cout << (ffind(i, a) == ffind(i, b) ? 1 : 0) << endl;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    分布式
    pytest+allure+jenkins
    Pytest-参数化和unittest-ddt的对比(两种数据驱动的对比)
    pytest- fixture个人理解总结
    os路径拼接时,比如os.path.join(base_dir,"Outputslogs")后半段斜杠请小心被识别为转义字符,所以请用/,因为windows都能识别到此路径。
    python中如何获取当前时间,并计算时间差
    Web UI自动化测试-滚动条操作
    java 基础 1.什么是Java?2.Java语言的特点?
    java 排序3 插入排序
    java 排序2 冒泡排序
  • 原文地址:https://www.cnblogs.com/quanjun/p/15523414.html
Copyright © 2011-2022 走看看