设为首页 加入收藏

TOP

C++算法之旅、05 基础篇 | 第二章 数据结构(四)
2023-09-09 10:25:34 】 浏览:229
Tags:
r (int i = 30; i >= 0; i--) { int bit = x >> i & 1; if (son[p][!bit]) { bit = !bit; } p = son[p][bit]; res = (res << 1) + bit; } return res; } int main() { int n; cin >> n; int m = 0; while (n--) { int x; cin >> x; insert(x); m = max(x ^ query(x), m); } cout << m; return 0; }

并查集

操作

  • 将两个集合合并
  • 询问两个元素是否在一个集合当中

朴素算法下,合并两个集合需要执行\(O(n+m)\)次;并查集可以近乎\(O(1)\)合并两个集合

基本原理

  • 用树的形式维护所有集合;根节点是集合编号
  • 每个节点存储父节点,p[x] 表示x的父节点

如何判断树根

  • if (p[x] == x) ,根节点的父节点是它本身

如何求x的集合编号

  • while(p[x] != x) x = p[x]
  • 路径压缩? :往上走找到根节点把路径所有点都指向根节点

如何合并两个集合 ? 记住模板

  • p[x] = y,将一颗树根节点插到另一棵树的某个位置
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

如何维护集合元素个数(携带额外信息)

  • 见837题

836 ?

836. 合并集合 - AcWing题库

#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int p[N];

// ^ 返回x祖宗节点 + 路径压缩
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main() {
    cin.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) p[i] = i;

    while (m--) {
        char op;
        int a, b;
        cin >> op >> a >> b;
        if (op == 'M') {
            p[find(a)] = find(b);
        } else {
            if (find(a) == find(b))
                puts("Yes");
            else
                puts("No");
        }
    }
    return 0;
}

837 ??

837. 连通块中点的数量 - AcWing题库

保证根节点的nums有意义

#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int p[N], nums[N];

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main() {
    cin.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        p[i] = i;
        nums[i] = 1;
    }
    while (m--) {
        string op;
        int a, b;
        cin >> op;
        if (op == "C") {
            cin >> a >> b;
            // ^ 特判
            if (find(a) == find(b)) continue;
            // ^ 先算元素个数再合并
            nums[find(b)] += nums[find(a)];
            p[find(a)] = find(b);
        } else if (op == "Q1") {
            cin >> a >> b;
            if (find(a) == find(b))
                puts("Yes");
            else
                puts("No");
        } else if (op == "Q2") {
            cin >> a;
            cout << nums[find(a)] << endl;
        }
    }
    return 0;
}

240 ???

240. 食物链 - AcWing题库

确定每个动物跟领袖(n对1)的关系,而不是动物跟动物(n对n)的关系

维护每个节点与根节点的距离(x吃y,y到x距离是1),然后 % 3 判断类型。初始化每个节点都是0,各自一类。

  • 余1:可以吃根节点
  • 余2:可以被根节点吃
  • 余0:与根节点是同类
#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int p[N], d[N];

int find(int x) {
    if (p[x] != x) {
        // 递归处理所有祖宗节点,并更新到根的距离
        int t = find(p[x]);
        // d[x] 等于 x到父的距离 + 父到根的距离(递归处理完了)
        d[x] += d[p[x]];
        // x 的父修改为根节点,路径优化
        p[x] = t;

        // // 记录旧的父
        // int u = p[x];
        // // 路径压缩,新父根节点
        // p[x] = find(p[x]);
        // // x到根的距离等于x到旧父距离加上旧父到根的距离
        // d[x] += d[u];
    }
    return p[x];
}

int main() {
    cin.tie(0);
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++) p[i] = i;

    int count = 0;
    while (k--) {
        char t;
        int x, y;
        cin >> t >> x >> y;
        if (x > n || y > n) {
            count++;
        } else {
            int px = find(x), py = find(y);
            if (t == '1') {
                if (px == py && (d[x] - d[y]) % 3 != 0)
                    count++;
                else if (px != py) {
                    p[px] = py;
                    d[px] = d[y] - d[x];  // IMPORTANT
                }
            } else {
                if (x == y || px == py && (d[x] - d[y] - 1) % 3 != 0) {
                    count++;
                } else if (px != py) {
                    p[px] = py;
                    d[px] = d[y] + 1 - d[x];
                }
            }
        }
    }
    cout << count << endl;

    return 0;
}

小根堆

每个点 <= 左右儿子,根节点就是树的最小值 。

完全二叉树用一维数组存:x 的左儿子 2x,x 的右儿子 2x+1;下标从1开始


两个操作 ?

  • down(x) 往下调整 (x是坐标 1 ~ size) \(O(log_2n)\)
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇乘法逆元及其三种求法 下一篇1.15 自实现GetProcAddress

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目