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

    洛谷P3402【模板】可持久化并查集

    思路:

    思路和可持久化线段树很相似,都是将主席树与另一种数据结构结合。这个是以并查集结合,所以维护数组fa和用于按秩合并的dep。

    首先要建一棵树,这棵树的叶子结点初始化成其对应的下标,即并查集中fa[i]=i的初始化操作

    然后对于查询操作,直接求对应历史版本的两个点是否fa相同即可

    连边操作:先找到两个点所在并查集的头结点,若它们已经在一个块中,就跳过,否则比较dep大小,按秩合并:将小的连向大的(将时间复杂度降到n*logn)

    若两个并查集的深度不同,则合并成一个后,深度为较大那个点的深度。若相同,需要把深度++(modify操作)

    学习博客

    #include<bits/stdc++.h>
    using namespace std;
    #define mid ((l+r)>>1)
    #define N 3000005
    int lc[N],rc[N],ndnum=0,dep[N],fa[N],n,ed[N];
    void build(int s,int l,int r)
    {
        //非叶子节点的fa[]为空 
        if(l==r) { fa[s]=l; return ; }//一开始每一个节点的父亲是自己 
        build(lc[s]=++ndnum,l,mid); build(rc[s]=++ndnum,mid+1,r);
    }
    int query(int s,int l,int r,int pos)
    {
        if(l==r) return s;
        if(pos<=mid) return query(lc[s],l,mid,pos);
        else return query(rc[s],mid+1,r,pos);
    }
    void modify(int s,int l,int r,int pos)
    {
        if(l==r){ dep[s]++; return ; }
        if(pos<=mid) modify(lc[s],l,mid,pos);
        else modify(rc[s],mid+1,r,pos);
    }
    void copynode(int a,int b)//在原来的基础上新增一条链 
    {
        lc[a]=lc[b]; rc[a]=rc[b];
    }
    void merge(int last,int &rt,int l,int r,int pos,int Fa)
        {
            rt=++ndnum;lc[rt]=lc[last],rc[rt]=rc[last];
            if(l==r)
            {
                fa[rt]=Fa;
                dep[rt]=dep[last];
                return ;
            }
            if(pos<=mid)merge(lc[last],lc[rt],l,mid,pos,Fa);
            else merge(rc[last],rc[rt],mid+1,r,pos,Fa);
        }
    int get_fa(int s,int pos)//找到的是对应点在主席树中的编号 fa[get_fa()]即为对应点的父亲 
    {
        int now=query(s,1,n,pos);//s==version??
        if(fa[now]==pos) return now;
        return get_fa(s,fa[now]);
    }
    int main()
    {
        int m,a,b,op;
        scanf("%d%d",&n,&m);
        build(ed[0]=++ndnum,1,n);
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                ed[i]=ed[i-1];//这里要复制前面的版本 
                scanf("%d%d",&a,&b);
                int f1=get_fa(ed[i],a); int f2=get_fa(ed[i],b);//f1 f2是对应的编号 
                if(fa[f1]==fa[f2]) continue;
                if(dep[f1]>dep[f2]) swap(f1,f2);
                merge(ed[i-1],ed[i],1,n,fa[f1],fa[f2]);//ed[i]是未知的 由最终merge后的节点编号决定 所以要打& 
                //若深度不同 那么深度是较深的一个 所以不需要改变 
                if(dep[f1]==dep[f2]) modify(ed[i],1,n,fa[f2]);//如果深度一样就需要将其中一个深度++ 
            }
            if(op==2) scanf("%d",&a),ed[i]=ed[a];
            if(op==3){
                scanf("%d%d",&a,&b);
                ed[i]=ed[i-1];//每一次记得把前一次的版本复制过来 
                int f1=get_fa(ed[i],a),f2=get_fa(ed[i],b);
                if(fa[f1]==fa[f2]) printf("1
    ");
                else printf("0
    ");
            }
        }
    }
    /*
    5 6
    1 1 2
    3 1 2
    2 0
    3 1 2
    2 1
    3 1 2
    */
  • 相关阅读:
    在visual studio 2010中调用ffmpeg
    RTP/RTCP/RTSP/SIP/SDP
    YV12数据与AVFrame的相互转换
    实现输出h264直播流的rtmp服务器
    RTMP协议发送H.264编码及AAC编码的音视频,实现摄像头直播
    CentOS 硬盘分区方案
    ubuntu默认root密码
    windows下ACE怎样安装与使用说明?
    CentOS 6.4 图文安装教程
    我自己的FFMpeg编译之路
  • 原文地址:https://www.cnblogs.com/mowanying/p/11402254.html
Copyright © 2011-2022 走看看