zoukankan      html  css  js  c++  java
  • bzoj 3673 可持久化并查集 by zky

    Description

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

    0<n,m<=2*10^4

    Input

     

    Output

     

    Sample Input

    5 6
    1 1 2
    3 1 2
    2 0
    3 1 2
    2 1
    3 1 2

    Sample Output

    1
    0
    1


    思路:
    用主席树去维护一个可持久化的数组,并查集的操作就变成了在这个可持久化数组上跳来跳去,
    连接两个点x,y就直接在主席树上下标为x点赋值为y,这样查询的时候只要一直跳就可以跳到根节点
    实现代码;
    #include<bits/stdc++.h>
    using namespace std;
    #define mid int m = (l + r) >> 1
    const int M = 2e6 + 10;
    
    int sum[M],ls[M],rs[M],dep[M],n,idx,root[M];
    void build(int l,int r,int &rt){
         rt = ++idx;
        if(l == r){
            sum[rt] = l;
            return ;
        }
        mid;
        build(l,m,ls[rt]); build(m+1,r,rs[rt]);
        return ;
    }
    
    void update(int old,int &rt,int p,int c,int l,int r){
        rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old];
        dep[rt] = dep[old];
        if(l == r){
            sum[rt] = c;
            return ;
        }
        mid;
        if(p <= m) update(ls[old],ls[rt],p,c,l,m);
        else update(rs[old],rs[rt],p,c,m+1,r);
    }
    
    int query(int p,int l,int r,int rt){
        if(l == r) return rt;
        mid;
        if(p <= m) return query(p,l,m,ls[rt]);
        else return query(p,m+1,r,rs[rt]);
    }
    
    void add(int p,int l,int r,int rt){
        if(l == r){
            dep[rt] ++;
            return;
        }
        mid;
        if(p <= m) add(p,l,m,ls[rt]);
        else add(p,m+1,r,rs[rt]);
    }
    
    int fd(int x,int rt){
        int pos = query(x,1,n,rt);
        if(x == sum[pos]) return pos;
        return fd(sum[pos],rt);
    }
    
    int main()
    {
        int q,op,x,y,k;
        scanf("%d%d",&n,&q);
        build(1,n,root[0]);
        for(int i = 1;i <= q;i ++){
            scanf("%d",&op);
            if(op == 1){
                scanf("%d%d",&x,&y);
                root[i] = root[i-1];
                int fx = fd(x,root[i-1]);
                int fy = fd(y,root[i-1]);
                if(sum[fx] == sum[fy]) continue;
                if(dep[fx] > dep[fy]) swap(fx,fy);
                update(root[i-1],root[i],sum[fx],sum[fy],1,n);
                if(dep[fx] == dep[fy]) add(sum[fy],1,n,root[i]);
            }
            else if(op == 2){
                scanf("%d",&k);
                root[i] = root[k];
            }
            else {
                root[i] = root[i-1];
                scanf("%d%d",&x,&y);
                int fx = fd(x,root[i]);
                int fy = fd(y,root[i]);
                if(sum[fx] == sum[fy]) printf("1
    ");
                else printf("0
    ");
            }
        }
        return 0;
    }
  • 相关阅读:
    营销运营中会遇到的名词及解释
    常用excel函数公式及操作示例
    opensuse安装pycharm
    Atom 基础使用
    git使用
    初学Python(第一课)
    django新手第一课
    浅谈session,cookie,sessionStorage,localStorage的区别及应用场景
    事件冒泡的应用
    django站点管理
  • 原文地址:https://www.cnblogs.com/kls123/p/9919076.html
Copyright © 2011-2022 走看看