• [算法模版]种类并查集


    [算法模版]种类并查集

    前言

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

    基本思想

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

    我们先把基础并查集中每个集合的元素都称作(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;
    }
    

    注意事项

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

  • 相关阅读:
    【BZOJ 3754】: Tree之最小方差树
    【cogs 775】山海经 ——Segment Tree
    【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】
    【BZOJ 2004】: [Hnoi2010]Bus 公交线路
    开启22端口
    将MySQL数据库表结构,自动生成PDM方法
    linux环境 创建多版本php
    mysql 数据类型选择浅谈
    int(5) 到底是多长
    (记)小程序如何发布
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/11739099.html
Copyright © 2020-2023  润新知