zoukankan      html  css  js  c++  java
  • [算法模版]种类并查集

    [算法模版]种类并查集

    前言

    众所周知,基本的并查集维护很多“集合”,同时可以对集合进行合并操作。而同一集合内的元素性质完全相等。但是如果我们不只需要维护相同的元素,还要维护不同元素之间的关系。那我们就可以使用种类并查集来处理。

    基本思想

    因为同一集合内元素性质完全相等,所以当集合中的一个元素确定了对另一个元素的关系时,我们也确定了这两个元素所在集合之间的关系。而在之前的普通并查集中,两个元素在同一个集合内代表他们完全相等。而这里我们需要更改这个规则。

    我们先把基础并查集中每个集合的元素都称作(A)类点,当我们需要维护两个集合之间某种关系时,我们就可以引入一种新的点——(B)类点。如果两个(A)类点处于同一集合,就代表他们完全相等,而如果一个(A)类点和一个(B)类点处于同一集合,就代表他们是另一种关系。这样我们就可以维护集合间的关系了。


    或者换种说法,每个点其实代表了所在集合的“性质”。性质相同的点会被合并。当你需要查找跟当前点是某种关系的集合时,只需要查找对应点所在的集合即可。

    例题

    NOI2001-食物链

    新建立两类点,并给他们分配新的编号来识别种类。(Bin[n+1,2n],Cin[2n+1,3n])

    当一个(A)类点和一个(B)类点处于同一集合,则代表(A)类点可以攻击(B)类点。而一个(A)类点和一个(C)类点处于同一集合,则代表(A)类点会被(C)类点攻击。

    #include<iostream>
    using namespace std;
    const int maxn=5e4+1000;
    int fa[maxn*3],n,k,ans;
    int get(int x) {
        if(fa[x]==x)return x;
        fa[x]=get(fa[x]);
        return fa[x];
    }
    void uni(int x,int y) {
        fa[get(x)]=get(y);
    }
    int main() {
        ios::sync_with_stdio(0);
        cin>>n>>k;
        for(int i=1;i<=3*n;i++)fa[i]=i;
        for(int i=1;i<=k;i++) {
            int ty,x,y;cin>>ty>>x>>y;
            if(x>n||y>n){ans++;continue;}
            if(ty==1) {
                if(get(x)==get(2*n+y)||get(x)==get(n+y)) {ans++;continue;}
                else {
                    uni(x,y);uni(x+n,y+n);uni(y+2*n,x+2*n);
                }
            }
            else {
                if(get(x)==get(y)||get(x)==get(y+n)){ans++;continue;}
                uni(n+x,y);uni(2*n+y,x);uni(2*n+x,n+y);
            }
        }
        cout<<ans;
    }
    

    注意事项

    需要注意的是,在查询的过程中,可以查询任意一个符合的条件即可(因为所有能推出的信息都已经推出)。而合并的时候则要合并所有能推出的信息。

  • 相关阅读:
    领会一些比较巧妙的算法
    操作系统os常识
    C++中的继承与虚函数各种概念
    我学shell程序的记录
    matlab:linux环境中将m文件编译成动态链接库
    struct内存对齐:gcc与VC的差别
    fedora中丢失或损坏fstab,无法启动,如何补救
    判断一个字符串中的字符是否都在另一个中出现
    linux下的不错的小软件:apvlv,zathura和vifm
    C语言中将结构体写入文件
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/11739099.html
Copyright © 2011-2022 走看看