并查集

 并查集

(Union/Find)主要涉及两种基本操作:合并和查找。

基本操作位合并之后,为查找某两个元素是否已经处在同一个集合中,需要Find操作。

我们可以将并查集的元素看成是一个树,也可以看成是一个集合

int mset[maxn];

//初始化
void init()
{
    for(int i=0;i<=15000;i++)mset[i]=i;
}
//find函数,常常可以在查找根结点时来修改一些量的值
int find(int a)
{
    return mset[a]==a?a:find(mset[a]);
}
//合并操作,在合并时可以进行需要合并过程中的一些操作
void uni(int a,int b)
{
    a=find(a);b=find(b);
    if(a<b)mset[b]=a;           //可添加其他操作
    if(b<a)mset[a]=b;
}

用途:

1.处理联通分支,联通量相关问题。比方说给定一个堆独立的树(即森林),对森林中的许多树进行union操作之后,整个树的个数将会减少,现在我们将每个树中的信息维护到每个树的根结点,利用根结点来处理整个树以至于整个森林中的信息。

HDU - 4619

这个题就是每个卡牌相当于一条边,卡牌的重叠就是边的连接,最后形成联通分支。在每个联通分支中维护行边和列边的个数,最后统计每个树中行列个数更多的那一个求和,将所有信息维护到每个树的根结点中。

//结构过程示例
int main()
{
    init();                 //初始化
    for(int i=1;i<=n;i++)   //合并边 并在合并过程中处理各种信息
        uni();

    for(int i=1;i<=n;i++)   //获得每个树中信息
        if(mset[i]==i)
            getresult();
}

 

带权并查集

带权并查集,即对于同一个并查集中的多个元素之间存在另外一种置换群关系

//关系种类数  记得修改
int relmod=2;
//并查集类
struct Mset
{
    int fa;
    int rel;
};
Mset mset[maxn];

//并查集初始化
void init()
{
    for(int i=0;i<=n;i++)
    {
        mset[i].fa=i;
        mset[i].rel=0;
    }
}

//查找a的根结点,并路径压缩,同时修改对父亲的rel
int find(int a)
{
    if(mset[a].fa==a)
        return a;

    int root=find(mset[a].fa);   //查找父亲

    mset[a].rel=(mset[a].rel+mset[mset[a].fa].rel)%relmod;  //修改对关系
    return mset[a].fa=root;   //修改父亲
}

//合并子集,基于向量的关系
void uni(int a,int b,int rel)
{
    int roota=find(a);
    int rootb=find(b);
    if(roota<rootb)
    {
        mset[rootb].fa=roota;
        mset[rootb].rel=(relmod+relmod-mset[b].rel-rel+mset[a].rel)%relmod;
    }
    else
    {
        mset[roota].fa=rootb;
        mset[roota].rel=(relmod-mset[a].rel+rel+mset[b].rel)%relmod;
    }
}

//查找同一棵树中的两种个元素之间a->b的关系
int getrel(int a,int b)
{
    int roota=find(a);
    int rootb=find(b);

    if(roota!=rootb)
        return -1;

    return (mset[a].rel+relmod-mset[b].rel)%relmod;
}

 

 

上一篇:jQuery模糊选择


下一篇:给基表添加路径的set_rel_pathlist