ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

(带权)并查集学习笔记

2021-08-25 08:35:49  阅读:168  来源: 互联网

标签:val int 查集 Rx Ry 笔记 fa 带权 Find


\[\huge 并查集 \]


\[\Large\rm 算法简介 \]

\(\quad\)并查集可以用来维护一类具有传递性的关系,维护形如将 \(x\) 与 \(y\) 所在集合合并和询问 \(x\) 和 \(y\) 是否在同一个集合的操作。

\(\large\rm 查询祖先节点\)

\(\quad\)对于普通并查集来说,有路径压缩和按秩合并等优化,路径压缩一般实现如下 :

int Find (int x) {
    if (x != fa[x]) fa[x] = Find(fa[x]);
    return fa[x];
}

\(\quad\)按秩合并则取点数小的连向点数大的即可。

\(\quad\)而对于带边权的并查集,我们需要在路径压缩的时候考虑加上其父亲的权值以维护其到根的差值,有路径压缩优化的带权并查集一般实现如下 :

int Find (int x) {
    if (x != fa[x]) {
        int mark = fa[x];
        fa[x] = Find(fa[x]), val[x] += val[mark];
    }
    return fa[x];
}

\(\quad\)由于路径压缩后 \(x\) 的父亲就是根节点了,所以需要记录其父亲到根的总权值并加到它的边权上。

\(\quad\)另外,如果要查询某个点 \(x\) 到根的权值和,由于一次路径压缩以后 \(x\) 的父亲会变成根,而此时的 \(val_x\) 就是路径和,所以可以先调用一次 Find(x),此时的 \(val_x\) 即为答案。

\(\large\rm 合并两个结点所在集合\)

\(\quad\)对于普通并查集来说,两个集合合并直接将其中一个根节点接到另一个根节点上即可。

\(\quad\)而对于带权并查集而言,我们必须求出需要连接的两个根节点之间连边的权值,而这个权值是可以直接确定的,假设现在要给 \(x\to y\) 连一条长度为 \(w\) 的边,设 \(x\) 的祖先为 \(Rx\),则 \(val_{Rx}=val_y+w-val_x.\) 另外,如果 \(x\) 和 \(y\) 已经在同一个集合中,并且 \(val_{Rx}+val_x-val_y\not = w\),则这条连边不合法。实现如下 :

bool Merge (int x, int y, int w) {
    int Rx = Find(x), Ry = Find(y);
    if (Rx != Ry) fa[Rx] = Ry, val[Rx] = val[y] + w - val[x];
    return val[Rx] + val[x] - val[y] == w;
}

\(\large\rm 模板\)

\(\quad\)带路径压缩和按秩合并优化的普通并查集 :

int Find (int x) {
    if (x != fa[x]) fa[x] = Find(fa[x]);
    return fa[x];
}

bool Merge (int x, int y) {
    int Rx = Find(x), Ry = Find(y);
    if (x != y) {
        if (pnum[Rx] < pnum[Ry])
            fa[Rx] = Ry, pnum[Ry] += pnum[Rx];
        else fa[Ry] = Rx, pnum[Rx] += pnum[Ry];
    }
    return Rx != Ry;
}

\(\quad\)带路径压缩和按秩合并优化的带权并查集 :

int Find (int x) {
    if (x != fa[x]) {
        int mark = fa[x];
        fa[x] = Find(fa[x]), val[x] += val[mark];
    }
    return fa[x];
}

int Diff (int x) {
    Find(x);
    return val[x];
}

bool Merge (int x, int y, int w) {
    int Rx = Find(x), Ry = Find(y);
    if (Rx != Ry) {
        if (pnum[Rx] < pnum[Ry])
            fa[Rx] = Ry, pnum[Ry] += pnum[Rx], val[Rx] = val[y] + w - val[x];
        else fa[Ry] = Rx, pnum[Rx] += pnum[Ry], val[Ry] = val[x] + w - val[y];
        return true;
    }
    if (Rx == Ry) return val[Rx] + val[x] - val[y] == w;
}

标签:val,int,查集,Rx,Ry,笔记,fa,带权,Find
来源: https://www.cnblogs.com/C-C-A/p/15183327.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有