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

    (题面来自洛谷)

    题目描述
    n个集合 m个操作

    操作:
    1 a b 合并a,b所在集合

    2 k 回到第k次操作之后的状态(查询算作操作)

    3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

    (n le 10^5, m le 2 imes 10^5)

    考虑不带路径压缩、使用启发式合并的并查集,每一次合并实际上只是改变了两个点的信息。
    1. v的父亲置为u
    2. (size(u) += size(v))

    那么将数组fa、size改为可持久化数组维护即可。
    复杂度分析:根据启发式合并性质,每次Find操作会执行(logn)次循环,循环中为可持久化数组查询,故Find操作的单次复杂度为(O(log^2n))

    代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    typedef long long LL;
    const int maxn(200010);
    int n, m;
    struct Seg_tree {
        #define mid ((l + r) >> 1)
        #define lc(nd) seg[nd].lc
        #define rc(nd) seg[nd].rc
        
        struct node {
            int dat, lc, rc;
        /*    node(int a = 0, int b = 0, int c = 0):
            	dat(a), lc(b), rc(c) {}*/
        //    node(): dat(0), lc(0), rc(0) {}
        } seg[maxn * 40];
        int root[maxn], tot;
        void modify(int& nd, int pre, int l, int r, int pos, int x) {
            nd = ++tot;
            seg[nd] = seg[pre];
            if (l == r) {
                seg[nd] = (node) {x, 0, 0};
                return;
            }
            if (pos <= mid) modify(lc(nd), lc(pre), l, mid, pos, x);
            else modify(rc(nd), rc(pre), mid+1, r, pos, x);
        }
        void build(int &nd, int l, int r, int val) {
        	nd = ++tot;
        	if (l == r) {
        		seg[nd] = (node) {val, 0, 0};
        		return;
        	}
        	build(lc(nd), l, mid, val);
        	build(rc(nd), mid+1, r, val);
        	return;
        }
        int query(int nd, int l, int r, int pos) {
            if (!nd) return 0;
            if (l == r) return seg[nd].dat;
            if (pos <= mid) return query(lc(nd), l, mid, pos);
            return query(rc(nd), mid+1, r, pos);
        }
    } Dsu, Siz;
    int Find(int x, int ver) {
        int tmp;
        while (tmp = Dsu.query(Dsu.root[ver], 1, n, x)) x = tmp;
        return x;
    }
    inline void merge(int u, int v, int ver) {
        u = Find(u, ver), v = Find(v, ver);
        if (u == v) return;
        int a, b;
        if ((a = Siz.query(Siz.root[ver], 1, n, u)) < (b = Siz.query(Siz.root[ver], 1, n, v))) swap(u, v);
        Dsu.modify(Dsu.root[ver], Dsu.root[ver-1], 1, n, v, u);
        Siz.modify(Siz.root[ver], Siz.root[ver-1], 1, n, u, a + b);
        return;
    }
    int main() {
    //	freopen("test.in", "r", stdin);
    //	freopen("test.ans", "w", stdout);
        scanf("%d %d", &n, &m);
        Siz.build(Siz.root[0], 1, n, 1);
        int op, u, v;
        for (int i = 1; i <= m; ++i) {
            scanf("%d %d", &op, &u);
            if (op == 1) {
            	Siz.root[i] = Siz.root[i-1];
    			Dsu.root[i] = Dsu.root[i-1];
                scanf("%d", &v);
                merge(u, v, i);
            } else if (op == 2) {
                Siz.root[i] = Siz.root[u];
    			Dsu.root[i] = Dsu.root[u];
            } else {
            	Siz.root[i] = Siz.root[i-1];
    			Dsu.root[i] = Dsu.root[i-1];
                scanf("%d", &v);
                putchar(Find(u, i) == Find(v, i) ? '1' : '0');
                putchar('
    ');
            }
        }
        return 0;
    }
    
  • 相关阅读:
    day_01 python基础 基本数据类型 if条件
    计算多边形周长和面积
    我研究出来的属性查询,贴自己的代码,请大家指教
    配置sde
    如何编辑SDE数据库(转载)
    ArcSED连接方式
    不同窗体传递数据
    sde stuff
    ArcSED
    不显示查询问题的解决(太完美了,新建一个图层,表示查询结果)
  • 原文地址:https://www.cnblogs.com/TY02/p/12267758.html
Copyright © 2011-2022 走看看