用户工具

站点工具


2020-2021:teams:no_morning_training:shaco:知识点:数据结构:并查集

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:no_morning_training:shaco:知识点:数据结构:并查集 [2020/06/30 11:45]
shaco
2020-2021:teams:no_morning_training:shaco:知识点:数据结构:并查集 [2020/07/06 09:15] (当前版本)
shaco
行 3: 行 3:
 并查集应用广泛,用于判断元素是否属于同一个集合以及合并集合。 并查集应用广泛,用于判断元素是否属于同一个集合以及合并集合。
 ==== 复杂度 ==== ==== 复杂度 ====
-最坏到 $O(n)$,单独使用路径压缩达到 $O(n+f(1+\log_{2+f/​n}n))$,单独使用按秩合并可达到 $O(\log{n})$,两者同时使用可以达到 $O(\alpha (n))$,其中 $\alpha (n)$ 是阿克曼函数的反函数,可以认为非常小(这部分参照网上)。按秩合并即每次将小的集合合并到大的集合中去,可以减少修改次数。+最坏到 $O(n)$,单独使用路径压缩达到 $O(n+f(1+\log_{2+f/​n}n))$,单独使用按秩合并可达到 $O(\log{n})$,两者同时使用可以达到 $O(\alpha (n))$,其中 $\alpha (n)$ 是阿克曼函数的反函数,可以认为非常小。按秩合并即每次将小的集合合并到大的集合中去,可以减少修改次数。
 ==== 概念 ==== ==== 概念 ====
 每个集合有一个代表元素,每一个元素通过一个数组记录其所属集合的代表元素。判断两个元素是否属于同一个集合时查询它们的代表元素是否相同,合并集合时将一个集合的代表元素更替为另一个集合的代表元素。 每个集合有一个代表元素,每一个元素通过一个数组记录其所属集合的代表元素。判断两个元素是否属于同一个集合时查询它们的代表元素是否相同,合并集合时将一个集合的代表元素更替为另一个集合的代表元素。
行 105: 行 105:
 <hidden code> <hidden code>
 <code cpp> <code cpp>
 +#​include<​cstdio>​
 +#​include<​algorithm>​
 +using namespace std;
 +int t,​n,​intr,​fa[2005][2],​m[2005];​
 +int Find(int x)
 +{
 +    if(fa[x][0]==x) return x;
 +    int f=Find(fa[x][0]);​
 +    fa[x][1]=!(fa[x][1]^fa[fa[x][0]][1]);​
 +    return fa[x][0]=f;
 +}
 +int Merge(int x,int y)
 +{
 +    int fx=Find(x),​fy=Find(y);​
 +    if(fx==fy)
 +    {
 +        if(fa[x][1]==fa[y][1])
 +            return 0;
 +        return 1;
 +    }
 +    if(m[fx]>​m[fy]) swap(fx,​fy),​swap(x,​y);​
 +    m[fy]+=m[fx];​
 +    fa[fx][0]=fy;​
 +    fa[fx][1]=!(fa[x][1]^(!fa[y][1]));​
 +    return 1;
 +}
 +int main()
 +{
 +    scanf("​%d",&​t);​
 +    for(int T=1;​T<​=t;​T++)
 +    {
 +        scanf("​%d%d",&​n,&​intr);​
 +        for(int i=1;​i<​=n;​i++)
 +        {
 +            fa[i][0]=i;
 +            m[i]=fa[i][1]=1;​
 +        }
 +        int v=1;
 +        for(int i=1,​a,​b;​i<​=intr;​i++)
 +        {
 +            scanf("​%d%d",&​a,&​b);​
 +            v&​=Merge(a,​b);​
 +        }
 +        if(T>1) printf("​\n\n"​);​
 +        printf("​Scenario #​%d:​\n",​T);​
 +        if(v) printf("​No suspicious bugs found!"​);​
 +        else printf("​Suspicious bugs found!"​);​
 +    }
 +    return 0;
 +}
 +
 </​code>​ </​code>​
 </​hidden>​ </​hidden>​
 ==== poj 1182 食物链 ==== ==== poj 1182 食物链 ====
 [[http://​poj.org/​problem?​id=1182|poj1182]] [[http://​poj.org/​problem?​id=1182|poj1182]]
 +
 +题意:有三种动物,处在一个捕食循环上($1\to2\to3\to1$),给出若干组捕食或者同类关系,判断假话的数量。假话即是与之前的非假话矛盾的话或不符合数据范围条件的话(这条不是重点)。
 +
 +这一题也是带权值,处理方式和上一题相似,关键在于处理好权值之间的计算关系。
 +
 +<hidden code>
 +<code cpp>
 +#​include<​cstdio>​
 +#​include<​algorithm>​
 +using namespace std;
 +int n,​k,​d,​x,​y,​ans=0,​fa[50005][2],​m[50005];​
 +int Find(int x)
 +{
 +    if(fa[x][0]==x) return x;
 +    int f=Find(fa[x][0]);​
 +    fa[x][1]=(fa[x][1]+fa[fa[x][0]][1])%3;​
 +    return fa[x][0]=f;
 +}
 +int Merge(int d,int x,int y)
 +{
 +    if(x>​n||y>​n||(d&&​x==y)) return 1;
 +    int fx=Find(x),​fy=Find(y);​
 +    if(fx==fy)
 +    {
 +        if((fa[x][1]+d+3)%3==fa[y][1]) return 0;
 +        return 1;
 +    }
 +    if(m[fx]>​m[fy]) swap(fx,​fy),​swap(x,​y),​d=-d;​
 +    m[fy]+=m[fx];​
 +    fa[fx][0]=fy;​
 +    fa[fx][1]=(fa[y][1]-d-fa[x][1]+3)%3;​
 +    return 0;
 +}
 +int main()
 +{
 +    scanf("​%d%d",&​n,&​k);​
 +    for(int i=1;​i<​=n;​i++)
 +    {
 +        fa[i][0]=i;
 +        fa[i][1]=0;
 +        m[i]=1;
 +    }
 +    for(int i=1;​i<​=k;​i++)
 +    {
 +        scanf("​%d%d%d",&​d,&​x,&​y);​
 +        ans+=Merge(d-1,​x,​y);​
 +    }
 +    printf("​%d",​ans);​
 +    return 0;
 +}
 +</​code>​
 +</​hidden>​
 ===== 参考 ===== ===== 参考 =====
 [[https://​www.nowcoder.com/​profile/​2315431/​note/​detail/​316067]] [[https://​www.nowcoder.com/​profile/​2315431/​note/​detail/​316067]]
2020-2021/teams/no_morning_training/shaco/知识点/数据结构/并查集.1593488702.txt.gz · 最后更改: 2020/06/30 11:45 由 shaco