OVSolitario-io

导航

染色法&并查集:维护不想交集合森林(维护传递性)

染色法
对于p1551亲戚,可并查集,这里考虑朴素染色法
Screenshot 2024-07-19 at 00.02.30
通过颜色来判断是否为同一宗族,颜色相同即同一个

最开始每个人都有一个颜色,当AB为亲戚时,则要将AB染成一个颜色

复杂度:O(数学公式: $ n^{2} $),因为每次操作可能都为O(n)

这里存在的优化:启发式合并
启发式合并:每次选人少部分染色(合并到更多)

染色法的改进:
染色法改进:不去真的执行染色,将B的标记指向A,然后说其应染成A的颜色
Screenshot 2024-07-19 at 00.13.52

link 1 2,则将1,2连接,让2指向1,让3指向2····
即2应染为1颜色,3应染为2的颜色(则3最终应染成1的颜色),通过记录bin数组,记录了每个点应被染的颜色,最终求出整个图的染色方法

bin[1] = 0是它的不要染色,另一种写法是它自己指向自己(则说明它应该被染成1自己这种颜色
Screenshot 2024-07-19 at 00.18.23

bin数组即为并查集

并查集:维护传递性

对于图上DFS/BFS单次操作O(n),当只关心元素是否连通不考虑层级时,可以使用并查集(路径压缩)
截屏2025-09-02 07.14.11
并查集

  • 合并:将两个元素(集合)合并为一个集合
  • 查询:查询两个元素是否在同一个集合中

路径压缩:细长树一次查询变为短粗树

int find(int x) {//路径压缩
    return fa[x] == x ? x :
           fa[x] = find(fa[x]);//因为根结点指向自己
}

void merge(int x, int y) {//合并:插入元素并到根结点
    fa[find(x)] = find(y);
}

对于查询是否属于同一个集合,也可以使用find(),通过指向根结点可以有效降低树高

查询时,集合中元素无法保证严格执行find操作时,考虑find(x) == find(y)写法

并查集的优化(按秩合并):对于合并,显然是想让小的集合合并到大的集合上,按秩合并O(mα(m, n)),对于10^100量级操作<=5,线性

可以按照人数多少和树的深度判读

新的问题是无法在压缩时很好的更新秩,所以按秩合并时即不使用路径压缩

int find(int x) {//按秩合并后不使用路径压缩
    return fa[x] == x ? x : find(fa[x]);
}

void merge(int x, int y) {//将y合并到x里面
    x = find(x), y = find(y);
    if(x != y) {
        if(sz[x] < sz[y]) {//让y为秩小,将y插入x
            swap(x, y);
        }
        fa[y] = x;
        sz[x] += sz[y];//x家庭增加y家庭大小
    }
}

两种方式对比:
路径压缩易于书写,但破坏了原本树形结构

有些题即依赖原本树形结构,对于可持久化数组即依赖于原本树形结构

按秩合并保留了树结构,最坏时复更优,但代码量稍大

常见应用:
截屏2025-09-02 07.51.48

对于扩展域还可以维护复杂关系:如敌人的敌人是我的朋友···

P3958奶酪:并查集维护传递性构造集合,那么判断连通性判断是否在同一个集合即可
维护连通,对于中间空洞认为若连通则合并起来,对于题中的上下表面,采取建立虚拟结点,对虚拟结点进行连通即处理了上下表面问题,最后查看上下表面是否连通(同一集合)即可
截屏2025-09-02 08.04.34

点击查看代码
for(int i = 1; i <= n + 2; ++ i) fa[i] = i;//n+2存入虚拟结点

for(int i = 1; i <= n; ++ i) {
    cin >> x[i] >> y[i] >> z[i];
    if(z[i] + r >= h) merge(i, n + 2);//上表面
    if(z[i] - r <= 0) merge(i, n + 1);//下表面
    for(int j = 1; j <= i; ++ j) {
        if(getdis(x[i], y[i], z[i], x[j], y[j], z[j]) <= 4LL * r * r) {//判断距离
            merge(i, j);
        }
    }
    put(find(n + 1) == find(n + 2) ? "Yes" : "No");
}

判断距离:sqrt时,满足小于为2r即可
当为了消除sqrt的精度问题,采用(x - x1)^2+(y - y1)^2+(z- z1)^2 <= 2r^2等价的思路

带权并查集:路径压缩 + 前缀和:带权并查集

链接里面是大佬写的带权值并查集

posted on 2025-09-02 08:12  TBeauty  阅读(8)  评论(0)    收藏  举报