【模板】带权并查集

简介: 笔记

1. 奇偶游戏


239. 奇偶游戏30.png

题意: 依次给出多个区间的含 1 11 的个数的奇偶性,找出第一个不符合的答案的回答。


思路:


31.png

如此发现,传递性形同于异或,即将给定的区间【a,b】的奇偶性,可视为【1,a-1】区间和【1,b】区间的奇偶性的异或结果,这是因为异或的前缀和性质,读者可自行了解(简单理解:x xx xor x xx = 0 =0=0)。所以给定一个区间【a,b】的奇偶性,实际上可以转化为A − 1 A-1A−1和B BB的奇偶性。( 大写A AA 定义为前缀和序列:【1,a】区间)


由上转化,我们需要维护的是前缀和序列的奇偶性:


【a,b】奇:A − 1 A-1A−1 和 B BB不同类。(01,10)

【a,b】偶:A − 1 A-1A−1 和 B BB 同类。(00,11)

我们可以通过并查集维护这种具有连通性,传递性的关系。考虑如下:(为了书写简便,以下用A代替上述推导的A-1了)

32.png

定义边权d [ u ]:


d [ u ] = = 0 d[u]==0d[u]==0,表示 u uu 与父节点 p [ u ] p[u]p[u] 奇偶性同。

d [ u ] = = 1 d[u]==1d[u]==1,表示 u uu 与父节点 p [ u ] p[u]p[u] 奇偶性不同。

如图所示,A AA 与 p [ A ] p[A]p[A] 同,p [ A ] p[A]p[A] 与 r A rArA 不同,那么如何推得 A AA 与根节点 r A rArA 的关系也是不同呢?显然 d [ A ] d[A]d[A] xor d [ p [ A ] ] d[p[A]]d[p[A]] 就是答案。所以在路径压缩中,每个节点只需要做如上所述的异或运算即可得到和根节点的奇偶性关系。


那么在一个集合中,得到了每个节点和根节点的奇偶性关系,通过传递性,就可以知道该集合中的任意两个节点之间的关系了。


上述考虑完并查集的路径压缩以及同属一个集合之间节点的关系,现在考虑一下如何合并两个集合。


33.png34.png

读者可能会思考:上述判断不成立只有在同属于一个集合的情况下才会去判断,那么不属于一个集合然后合并的时候会不会存在矛盾呢?由于异或,由于传递性,是不会产生矛盾的。可以模拟一下各种情况。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <set> 
using namespace std;
const int N = 200010;
int n, m;
int p[N], d[N]; 
int a[N << 1];
int find(int x)  // 并查集
{
    if (p[x] != x) {
        int r = find(p[x]);
        // d[x] ^= d[p[x]]; // 路径压缩中的权值计算
        d[x] += d[p[x]]; d[x] %= 2;
        p[x] = r;
    }
    return p[x];
}
struct node {
    int a, b, c;
}; 
node f[N << 1]; 
/*
由于题目数据太大,所以这里需要离散化处理。
此程序采用set离散化,注意需要用到的值还包含x-1。
*/
int main()
{
    cin >> n >> m;
    for (int i = 0; i < N; i++) p[i] = i;
    set<int> s;
    for (int i = 0; i < m; i++) {
        int u, v; string c; cin >> u >> v >> c;
        int x;
        if (c == "odd") {
            x = 1;
        } else {
            x = 0;
        }
        f[i] = {u, v, x}; 
        s.insert(u), s.insert(v);
        s.insert(u - 1), s.insert(v - 1);
    }
    int idx = 0;
    for (auto c: s) a[++idx] = c;
    for (int i = 0; i < m; i++) {
        int u = f[i].a, v = f[i].b, c = f[i].c; 
        int A = lower_bound(a + 1, a + 1 + idx, u - 1) - a, B = lower_bound(a + 1, a + 1 + idx, v) - a;
        int fx = find(A), fy = find(B);
        bool o = true; 
        if (fx == fy) {
            // if ((d[A] ^ d[B]) != c) o = false;
            if ((d[A] + d[B]) % 2 != c) o = false; 
        } else {
            p[fx] = fy; 
            // d[fx] = d[A] ^ d[B] ^ c;
            d[fx] = d[A] + d[B] + c;
        }
        if (!o) {
            cout << i << endl;
            return 0;
        }
    }
    cout << m << endl; 
    return 0;
}

2. 银河英雄传说


238. 银河英雄传说

35.png

思路:

36.png


代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e6 + 10;
int p[N], dis[N], siz[N];
int find(int x)  // 并查集
{
    if (p[x] != x) {
        int r = find(p[x]);
        dis[x] += dis[p[x]];
        p[x] = r;
    }
    return p[x];
}
int main()
{
    int n; scanf("%d", &n); 
    for (int i = 0; i < N; i++) siz[i] = 1, p[i] = i;
    int a, b; char op[2];
    for (int i = 0; i < n; i++) {
        scanf("%s%d%d", &op, &a, &b);
        int fx = find(a), fy = find(b);
        if (op[0] == 'M') {
            if (fx != fy) {
                p[fx] = fy;
                dis[fx] = siz[fy];
                siz[fy] += siz[fx];
            }
        } else {
            if (fx != fy) { printf("-1\n"); }
            else printf("%d\n", max(0, abs(dis[b] - dis[a]) - 1));
        }
    }
    return 0;
}
相关文章
|
开发者 iOS开发
【教程】无法验证 app 需要互联网连接以验证是否信任开发者
【教程】无法验证 app 需要互联网连接以验证是否信任开发者
|
7月前
|
开发工具 Windows
dotnet-sdk-10.0.100-win-x64.exe 怎么安装?Win10/Win11 安装步骤教程
本文介绍了在64位Windows系统上安装.NET SDK 10.0.100的完整步骤。首先下载安装包,双击运行并同意许可协议,按提示完成安装。可选自定义安装路径或使用默认设置。安装后可通过“Win+R”输入cmd,执行`dotnet --version`命令验证是否成功安装,显示版本号即表示安装成功。
1629 0
|
SQL 自然语言处理 关系型数据库
MySQL的match匹配多个字符串的语法
【8月更文挑战第27天】MySQL的match匹配多个字符串的语法
717 67
|
5月前
|
存储 缓存 安全
阿里云活动内云服务器实例规格有何区别?e/u2a/c9i/g9i/r9i实例性能介绍与选择参考
本文介绍了阿里云服务器中经济型e、通用算力型u2a、计算型c9i、通用型g9i、内存型r9i五类实例的性能特点、适用场景及选择参考。经济型e实例适合中小型网站建设及开发测试;通用算力型u2a基于AMD平台,适合中小企业级应用;计算型c9i适配机器学习推理等高计算场景;通用型g9i满足多场景企业级需求;内存型r9i适合实时大数据分析。用户可根据应用场景、性能需求及预算综合选择。
|
存储 关系型数据库 MySQL
MySQL中为什么要使用索引合并(Index Merge)?
通过这些内容的详细介绍和实际案例分析,希望能帮助您深入理解索引合并及其在MySQL中的
851 10
|
SQL 关系型数据库 MySQL
MySQL语法
MySQL语法
387 4
|
存储 关系型数据库 MySQL
MySQL的优化利器⭐️Multi Range Read与Covering Index是如何优化回表的?
本文以小白的视角使用通俗易懂的流程图深入浅出分析Multi Range Read与Covering Index是如何优化回表
|
消息中间件 存储 缓存