素集合データ構造

目的

$n$個の相異なる要素からなる共通部分を持たない集合について、集合の合併と、ある要素同士が同一集合に含まれるかの判定を$O(\alpha(n))$で行います。 ここで、$\alpha$はアッカーマンの逆関数。

計算量

$O(\alpha(n))$

使い方

integer n
全要素数
integer[] upper
素集合データ構造はデータを根付き木で管理します。upper[x]≥0ならば、xの親はupper[x]です。upper[x]<0ならばxを根とする木の大きさは-upper[x]です。
integer root(integer u)
uの親をreturnします。uが根である場合はu自身をreturnします。
void setUnion(integer x,integer y)
xを含む集合とyを含む集合を合併します。
void build(integer n_)
n=n_としてupper配列を用意します。

ソースコード

module djset_md
    private
    type,public::DJSet
        integer::n
        integer,allocatable::upper(:)
    contains
        procedure::build=>build_
        procedure::root=>root_
        procedure::setUnion=>setUnion_
    end type

contains
    subroutine build_(o,n_)
        implicit none
        integer::i,j,k
        class(DJSet)::o
        integer::n_
        o%n=n_
        allocate(o%upper(o%n))
        do i=1,o%n
            o%upper(i)=-1
        end do
    end subroutine

    recursive function root_(o,x)result(res)
        implicit none
        class(DJSet)::o
        integer::x,res
        if(o%upper(x)<0)then
            res=x
        else
            o%upper(x)=o%root(o%upper(x))
            res=o%upper(x)
        end if
    end function

    subroutine setUnion_(o,x,y)
        implicit none
        class(DJSet)::o
        integer::x,y
        x=root_(o,x)
        y=root_(o,y)
        if(x==y)return
        if(o%upper(x)<o%upper(y).or.(o%upper(x)==o%upper(y).and.x<y))then
            x=xor(x,y)
            y=xor(x,y)
            x=xor(x,y)
        end if
        o%upper(y)=o%upper(x)+o%upper(y)
        o%upper(x)=y
    end subroutine
end module