并查集分析与扩展

http://jarily.com/acm/2012/11/26/bcj.html

一 并查集的基础

1 基本功能

并查集用于处理不相交数据集合;

2 基本操作

(1)查找一个元素的祖先(即查找这个元素属于哪个集合);
(2)将两个元素所在的集合合并为一个集合;
(3)删除操作,即把某个元素从它所在的集合中删除;

3 基本代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int N=30030;
int n;
int f[N],rank[N],num[N];

void init()//初始化
{
    for(int i=1; i<=n; i++)
        f[i]=i;
}

int getFather(int x)//查找元素x的祖先
{
    if(f[x]==x)
        return f[x];
    f[x]=getFather(f[x]);//路径压缩
    return f[x];
}

void unionSet(int x,int y)//将两个元素所在的集合合并为一个集合
{
    int xx=getFather(x),yy=getFather(y);
    if(xx!=yy)
        f[xx]=yy;
}

二 并查集的扩展

1 记录每个集合的元素个数

在此初始化以及合并集合的时候处理一下集合的元素个数即可;

代码
void _init()
{
    int i;
    for(i=1; i<=n; i++)
        f[i]=i,num[i]=1;
}

void _unionSet(int x,int y)
{
    int xx=getFather(x),yy=getFather(y);
    if(xx!=yy)
        f[xx]=yy,num[yy]+=num[xx];
}

2 并查集的删除

即把某个元素从它所在的集合中删除; 
即生成若干个超级父亲,每个节点的父亲都是一个超级父亲; 
删除就直接令自己的父亲等于自己;

代码
int s;
void __init()
{
    for(int i=1; i<=n; i++)
        f[i]=i;
    s=n+1;
}

int __getFather(int x)
{
    if(f[x]==x)
        return f[x];
    f[x]=getFather(f[x]);
    return f[x];
}

void __unionSet(int x,int y)
{
    int xx=getFather(x),yy=getFather(y);
    if(xx!=yy)
    {
        if(xx>n)
            f[yy]=xx;
        else if(yy>n)
            f[xx]=yy;
        else
            f[xx]=s,f[yy]=s,f[s]=s,s++;
    }
}

void deleteX(int x)
{
    f[x]=x;
}

3 rank数组的应用;

其基本定义是一个元素到它的祖先的路径长度;

三 算法应用-HDU2818;

1 题目链接

Building Block

2 题目大意

有n个箱子,然后是两种操作:

(1)把x所在的那一摞箱子搬到y所在的那一摞上面;
(2)询问x的下面有几个箱子;

3 代码

int getF(int x)
{
    if(f[x]==x)
        return x;
    int t=f[x];//做完getFather之后再更新rank
    f[x]=getF(f[x]),rank[x]+=rank[t];//rank[x]代表x到它的祖先的距离,即x的上面还有几个箱子
    return f[x];
}

int main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);
    char te[5];
    while(~scanf("%d",&n))
    {
        for(int i=0; i<=30000; i++)
            f[i]=i,num[i]=1,rank[i]=0;
        for(int i=0; i<n; i++)
        {
            int x,y;
            scanf("%s",te);
            if(te[0]==‘M‘)
            {
                scanf("%d%d",&x,&y);
                int xx=getF(x);
                int yy=getF(y);
                if(xx!=yy)
                    f[yy]=xx,rank[yy]=num[xx],num[xx]+=num[yy];
            }
            else
            {
                scanf("%d",&x);
                printf("%d\n",num[getF(x)]-rank[x]-1);
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/shandongs1/p/8445074.html

时间: 2024-10-10 08:22:22

并查集分析与扩展的相关文章

POJ 2492 并查集应用的扩展

A Bug's Life Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 28651 Accepted: 9331 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and

【hiho】14 无间道之并查集【图论--并查集】

传送门:无间道之并查集 分析 并查集的分析可以看上面的传送门,写的挺好的了. 其实在我看来并查集就是一种方便的维护集合的一种技巧,提出了代表元素这一概念. My AC Code #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1e5+5; int represent[maxn]; int find_represent(int x) {

并查集扩展之最小生成树Kruskal算法

并查集有很多经典的应用.在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中. 其中一个非常经典的应用是最小生成树的Kruskal算法.给定一个具有n个节点的连通图,它的生成树是原图的一个子图,包含所有n个节点,且有保持图连通的最少的边(n-1条边).边权值最小的生成树是最小生成树. kruskal算法是一个贪心算法,把所有的边按权值从小到大依次考虑,如果当前边加进生成树中会出现回路

UVA - 12232 Exclusive-OR (并查集扩展偏离向量)

Description You are not given n non-negative integersX0,X1,..., Xn-1 less than220, but they do exist, and their values never change. I'll gradually provide you some facts about them, and ask you some questions. There are two kinds of facts, plus one

洛谷P1196[NOI2002]银河英雄传说-并查集扩展

银河英雄传说 题意:在并查集的基础上,还要求出同一集合的两个点的距离 这道题用并查集自己是知道的,但是竟然可以这么骚的操作. 下面转自大佬的查详细题解 初见这道题,首先想到的方法当然是直接模拟,模拟每一次指令.当然这种方法对于小数据行得通,但对于此题的500,000个指令,肯定超时. 因此我们就要想其它方法. 先来分析一下这些指令的特点,很容易发现对于每个M指令,只可能一次移动整个队列,并且是把两个队列首尾相接合并成一个队列,不会出现把一个队列分开的情况,因此,我们必须要找到一个可以一次操作合并

POJ 1182 (经典食物链 /并查集扩展)

(參考他人资料) 向量偏移--由"食物链"引发的总结 http://poj.org/problem?id=1182这道食物链题目是并查集的变型.非常久曾经做的一次是水过的,这次细致地研究了这"食物链",无非就是运用向量偏移.从曾经节点与节点转化成向量与向量的关系.我们能够把矛盾的产生得益于向量偏移时的结果. 直接引出向量偏移的运用. 以下是POJ一位大牛这样理解的,本人稍有改动. 对于集合里的随意两个元素a,b而言,它们之间必然存在着某种联系,由于并查集中的元素

hdu 3047(扩展并查集)

Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2672    Accepted Submission(s): 1028 Problem Description In 12th Zhejiang College Students Games 2007, there was a new stadium built

POJ 2492 并查集扩展(判断同性恋问题)

G - A Bug's Life Time Limit:10000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2492 Appoint description: Description BackgroundProfessor Hopper is researching the sexual behavior of a rare species of bugs. H

并查集简要分析

并查集:(union-find sets) 一种简单的用途广泛的集合. 并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等.最完美的应用当属:实现Kruskar算法求最小生成树. 并查集的精髓(即它的三种操作,结合实现代码模板进行理解): 1.MakeSet(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变). 2.FindSet(x) 查找一个元素所在的集合 查