扩展域并查集 带权并查集

[NOI2001] 食物链

题目描述

动物王国中有三类动物 A , B , C A,B,C A,B,C,这三类动物的食物链构成了有趣的环形。 A A A B B B B B B C C C C C C A A A

现有 N N N 个动物,以 1 ∼ N 1 \sim N 1N 编号。每个动物都是 A , B , C A,B,C A,B,C 中的一种,但是我们并不知道它到底是哪一种。

有人用两种说法对这 N N N 个动物所构成的食物链关系进行描述:

  • 第一种说法是 1 X Y,表示 X X X Y Y Y 是同类。
  • 第二种说法是2 X Y,表示 X X X Y Y Y

此人对 N N N 个动物,用上述两种说法,一句接一句地说出 K K K 句话,这 K K K 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

  • 当前的话与前面的某些真的话冲突,就是假话;
  • 当前的话中 X X X Y Y Y N N N 大,就是假话;
  • 当前的话表示 X X X X X X,就是假话。

你的任务是根据给定的 N N N K K K 句话,输出假话的总数。

输入格式

第一行两个整数, N , K N,K N,K,表示有 N N N 个动物, K K K 句话。

第二行开始每行一句话(按照题目要求,见样例)

输出格式

一行,一个整数,表示假话的总数。

样例 #1

样例输入 #1

100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5

样例输出 #1

3

提示

对于全部数据, 1 ≤ N ≤ 5 × 1 0 4 1\le N\le 5 \times 10^4 1N5×104 1 ≤ K ≤ 1 0 5 1\le K \le 10^5 1K105

题解

扩展域并查集详解

扩展域并查集是一种通过将每个元素拆分成多个域(或状态)来表示复杂关系的并查集方法。在食物链问题中,我们需要处理动物之间的同类关系和捕食关系,扩展域并查集通过将每个动物拆分成多个域来表示其可能的类别(如 ABC),从而高效地处理这些关系。


核心思想

  1. 拆分域

    • 每个动物 x 拆分成三个域:
      • x:表示动物 x 属于 A 类。
      • x + n:表示动物 x 属于 B 类。
      • x + 2n:表示动物 x 属于 C 类。
    • 这里的 n 是动物的总数,确保每个域的唯一性。
  2. 关系表示

    • 这里我们结合题意 A − > B − > C − > A A->B->C->A A>B>C>A的食物链,进行分析如下:
    • 如果动物 xy 是同类,那么它们的 ABC 域分别属于同一集合。因为题目中只有 A B C ABC ABC三个物种,同类的下一级物种不会互相吃,同类的天敌也不会互相吃,所以合并的时候需要把猎物和天敌一并更新。
    • 如果动物 xy,那么:
      • xA 域和 yC 域属于同一集合。
      • unity(x, y + 2 * n);//x的同类是y的天敌
      • xB 域和 yA 域属于同一集合。
      • unity(x + n, y);//x的猎物是y的同类
      • xC 域和 yB 域属于同一集合。这里可以在食物链里模拟一下就能理解。
      • unity(x + 2 * n, y + n);//x的天敌是y的猎物
  3. 矛盾检测

    • 如果当前说法与已维护的关系矛盾,则判断为假话。即同类不能与捕食关系共存。

具体步骤

1. 初始化
  • 初始化并查集,每个域独立成集合。
    for (int i = 1; i <= 3 * n; i++) {p[i] = i;
    }
    
2. 处理说法
  • 对于每种说法,检查是否与已维护的关系矛盾:
    • 说法 1xy 是同类。
      • 检查 xA 域是否与 yBC 域在同一集合。即没有捕食关系
      • 如果没有矛盾,合并 xyABC 域。
    • 说法 2xy
      • 检查 xA 域是否与 yAC 域在同一集合。即没有同类关系或者反向捕食关系。
      • 如果没有矛盾,合并 xA 域与 yB 域,xB 域与 yC 域,xC 域与 yA 域。
3. 假话统计
  • 如果说法与已维护的关系矛盾,则统计为假话。

代码实现

#include <iostream>
#include <vector>
using namespace std;const int MAXN = 50010;int p[MAXN * 3]; // 扩展域并查集,每个动物拆分为3个域// 查找函数,带路径压缩
int find(int x) {if (p[x] != x) {p[x] = find(p[x]);}return p[x];
}// 合并函数
void merge(int x, int y) {p[find(x)] = find(y);
}int main() {int n, k;cin >> n >> k;// 初始化扩展域并查集for (int i = 1; i <= 3 * n; i++) {p[i] = i;}int ans = 0; // 假话数量while (k--) {int t, x, y;cin >> t >> x >> y;// 越界或自吃,直接判断为假话if (x > n || y > n) {ans++;continue;}if (t == 2 && x == y) {ans++;continue;}if (t == 1) {// x和y是同类if (find(x) == find(y + n) || find(x) == find(y + 2 * n)) {ans++; // 矛盾} else {// 合并x和y的同类域merge(x, y);merge(x + n, y + n);merge(x + 2 * n, y + 2 * n);}} else {// x吃yif (find(x) == find(y) || find(x) == find(y + 2 * n)) {ans++; // 矛盾} else {// 合并x的A域和y的B域,x的B域和y的C域,x的C域和y的A域merge(x, y + n);merge(x + n, y + 2 * n);merge(x + 2 * n, y);}}}cout << ans << endl;return 0;
}

示例分析

输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
处理过程
  1. 说法 1 101 1101 越界,假话。
  2. 说法 2 1 212,合并 1A 域与 2B 域,1B 域与 2C 域,1C 域与 2A 域。
  3. 说法 2 2 323,合并 2A 域与 3B 域,2B 域与 3C 域,2C 域与 3A 域。
  4. 说法 2 3 333,自吃,假话。
  5. 说法 1 1 313 是同类,检查是否矛盾。如果 1A 域与 3BC 域在同一集合,则矛盾。
  6. 说法 2 3 131,检查是否矛盾。如果 3A 域与 1AC 域在同一集合,则矛盾。
  7. 说法 1 5 555 是同类,合法。
输出
3

总结

扩展域并查集通过拆分域来表示复杂关系,逻辑直观且易于理解。虽然空间开销较大,但在处理复杂关系问题时非常高效。

带权并查集详解

带权并查集是一种在普通并查集的基础上,为每个节点维护一个权值(或关系)的数据结构。通过权值,我们可以表示节点之间的复杂关系(如捕食关系、同类关系等)。在食物链问题中,带权并查集通过权值来表示动物之间的捕食关系,从而高效地判断给定的说法是否为假话。


核心思想

思想是没有合并到一起的集合不会产生矛盾。被合并的集合,有相同的集合代表,根据该点和集合代表点的关系推断。

  1. 权值定义

    • 每个节点 x 维护一个权值 d[x],表示 x 与其父节点 p[x] 的关系。
    • 权值的具体含义:
      • d[x] = 0xp[x] 是同类。
      • d[x] = 1xp[x]
      • d[x] = 2xp[x]吃。
  2. 路径压缩

    • 在查找根节点的过程中,路径压缩会将每个节点的父节点直接指向根节点,并更新权值 d[x],确保权值表示的是 x 到根节点的总关系。
  3. 关系推导

    • 通过权值的模运算,可以推导出任意两个节点之间的关系。
    • 例如:
      • 如果 d[x] = 1d[y] = 0,则 xy
      • 如果 d[x] = 2d[y] = 1,则 xy
  4. 合并操作

    • 当合并两个集合时,根据当前说法调整权值,确保合并后的关系正确。

具体步骤

1. 初始化
  • 初始化并查集,每个节点的父节点为自身,权值为 0
    for (int i = 1; i <= n; i++) {p[i] = i;d[i] = 0;
    }
    
2. 查找函数
  • 查找节点 x 的根节点,并在路径压缩的过程中更新权值。
    int find(int x) {if (p[x] != x) {int orig_p = p[x]; // 保存原始父节点p[x] = find(p[x]); // 递归找到根节点d[x] = (d[x] + d[orig_p]) % 3; // 更新权值}return p[x];
    }
    
3. 处理说法
  • 对于每种说法,检查是否与已维护的关系矛盾:
    • 说法 1xy 是同类。
      • 找到 xy 的根节点 rxry
      • 如果 rx == ry,检查 d[x]d[y] 是否相等。
      • 如果 rx != ry,合并两个集合,并调整权值。
    • 说法 2xy
      • 找到 xy 的根节点 rxry
      • 如果 rx == ry,检查 (d[x] - d[y] + 3) % 3 是否等于 1
      • 如果 rx != ry,合并两个集合,并调整权值。
4. 假话统计
  • 如果说法与已维护的关系矛盾,则统计为假话。

代码实现

#include <iostream>
#include <vector>
using namespace std;const int MAXN = 50010;int p[MAXN]; // 父节点数组
int d[MAXN]; // 权值数组,表示与父节点的关系// 查找函数,带路径压缩和权值更新
int find(int x) {if (p[x] != x) {int orig_p = p[x]; // 保存原始父节点p[x] = find(p[x]); // 递归找到根节点d[x] = (d[x] + d[orig_p]) % 3; // 更新权值}return p[x];
}int main() {int n, k;cin >> n >> k;// 初始化并查集for (int i = 1; i <= n; i++) {p[i] = i;d[i] = 0;}int ans = 0; // 假话数量while (k--) {int t, x, y;cin >> t >> x >> y;// 越界或自吃,直接判断为假话if (x > n || y > n) {ans++;continue;}if (t == 2 && x == y) {ans++;continue;}int rx = find(x), ry = find(y); // 找到x和y的根节点if (rx != ry) {// 合并两个集合p[rx] = ry;if (t == 1) {d[rx] = (d[y] - d[x] + 3) % 3; // x和y是同类} else {d[rx] = (d[y] - d[x] + 4) % 3; // x吃y}} else {// 同一集合内,检查关系是否矛盾if (t == 1 && (d[x] - d[y] + 3) % 3 != 0) {ans++;} else if (t == 2 && (d[x] - d[y] + 3) % 3 != 1) {ans++;}}}cout << ans << endl;return 0;
}

示例分析

输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
处理过程
  1. 说法 1 101 1101 越界,假话。
  2. 说法 2 1 212,合并 12 的集合,调整权值。
  3. 说法 2 2 323,合并 23 的集合,调整权值。
  4. 说法 2 3 333,自吃,假话。
  5. 说法 1 1 313 是同类,检查是否矛盾。
  6. 说法 2 3 131,检查是否矛盾。
  7. 说法 1 5 555 是同类,合法。
输出
3

总结

带权并查集通过维护权值来表示节点之间的关系,路径压缩和权值更新确保了高效的关系推导。虽然逻辑稍复杂,但代码简洁且高效,适合处理类似食物链的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12457.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL常用数据类型和表的操作

文章目录 (一)常用数据类型1.数值类2.字符串类型3.二进制类型4.日期类型 (二)表的操作1查看指定库中所有表2.创建表3.查看表结构和查看表的创建语句4.修改表5.删除表 (三)总代码 (一)常用数据类型 1.数值类 BIT([M]) 大小:bit M表示每个数的位数&#xff0c;取值范围为1~64,若…

DeepSeekMoE:迈向混合专家语言模型的终极专业化

一、结论写在前面 论文提出了MoE语言模型的DeepSeekMoE架构&#xff0c;目的是实现终极的专家专业化(expert specialization)。通过细粒度的专家分割和共享专家隔离&#xff0c;DeepSeekMoE相比主流的MoE架构实现了显著更高的专家专业化和性能。从较小的2B参数规模开始&#x…

寻迹传感器模块使用说明

产品用途&#xff1a; 1、电度表脉冲数据采样 2、传真机碎纸机纸张检测 3、障碍检测 4、黑白线检测 产品介绍: 1、采用 TCRT5000 红外反射传感器 2、检测反射距离&#xff1a;1mm~25mm 适用 3、比较器输出&#xff0c;信号干净&#xff0c;波形好&#xff0c;驱…

java项目验证码登录

1.依赖 导入hutool工具包用于创建验证码 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.5.2</version></dependency> 2.测试 生成一个验证码图片&#xff08;生成的图片浏览器可…

Baklib探讨如何通过内容中台提升组织敏捷性与市场竞争力

内容概要 在数字化转型的浪潮中&#xff0c;内容中台已经成为企业提升市场响应速度和竞争力的关键所在。内容中台不仅是信息处理的集结地&#xff0c;更是促进资源高效整合和灵活应用的重要平台。通过构建一个高效的内容中台架构&#xff0c;企业能够更好地应对不断变化的市场…

Java基础——分层解耦——IOC和DI入门

目录 三层架构 Controller Service Dao ​编辑 调用过程 面向接口编程 分层解耦 耦合 内聚 软件设计原则 控制反转 依赖注入 Bean对象 如何将类产生的对象交给IOC容器管理&#xff1f; 容器怎样才能提供依赖的bean对象呢&#xff1f; 三层架构 Controller 控制…

Spring中@Conditional注解详解:条件装配的终极指南

一、为什么要用条件装配&#xff1f; 在实际开发中&#xff0c;我们经常需要根据不同的运行环境、配置参数或依赖情况动态决定是否注册某个Bean。例如&#xff1a; 开发环境使用内存数据库&#xff0c;生产环境连接真实数据库 当存在某个类时才启用特定功能 根据配置文件开关…

Redis代金卷(优惠卷)秒杀案例-多应用版

Redis代金卷(优惠卷)秒杀案例-单应用版-CSDN博客 上面这种方案,在多应用时候会出现问题,原因是你通过用户ID加锁 但是在多应用情况下,会出现两个应用的用户都有机会进去 让多个JVM使用同一把锁 这样就需要使用分布式锁 每个JVM都会有一个锁监视器,多个JVM就会有多个锁监视器…

ros 发布Topic

1、确定话题名称和消息类型 自定义话题名称&#xff0c;消息类型根据发送消息需要从std_msgs中查找确定 2、在main函数中通过NodeHander发布话题 // 创建一个NodeHandle对象&#xff0c;用于与ROS系统进行交互ros::NodeHandle nh;// 创建一个Publisher对象&#xff0c;用于发…

86.(2)攻防世界 WEB PHP2

之前做过&#xff0c;回顾一遍&#xff0c;详解见下面这篇博客 29.攻防世界PHP2-CSDN博客 既然是代码审计题目&#xff0c;打开后又不显示代码&#xff0c;肯定在文件里 <?php // 首先检查通过 GET 请求传递的名为 "id" 的参数值是否严格等于字符串 "admi…

毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统

目录 前言 课题背景和意义 实现技术思路 一、算法理论基础 1.1 卷积神经网络 1.2 目标检测算法 1.3 注意力机制 二、 数据集 2.1 数据采集 2.2 数据标注 三、实验及结果分析 3.1 实验环境搭建 3.2 模型训练 3.2 结果分析 最后 前言 &#x1f4c5;大四是整个大学…

AI取代人类?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

刷题记录 动态规划-7: 63. 不同路径 II

题目&#xff1a;63. 不同路径 II 难度&#xff1a;中等 给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角&#xff08;即 grid[0][0]&#xff09;。机器人尝试移动到 右下角&#xff08;即 grid[m - 1][n - 1]&#xff09;。机器人每次只能向下或者向右移动一步。…

深度求索DeepSeek横空出世

真正的强者从来不是无所不能&#xff0c;而是尽我所能。多少有关输赢胜负的缠斗&#xff0c;都是直面本心的搏击。所有令人骄傲振奋的突破和成就&#xff0c;看似云淡风轻寥寥数语&#xff0c;背后都是数不尽的焚膏继晷、汗流浃背。每一次何去何从的困惑&#xff0c;都可能通向…

51c视觉~CV~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/13241694 一、CV创建自定义图像滤镜 热图滤镜 这组滤镜提供了各种不同的艺术和风格化光学图像捕捉方法。例如&#xff0c;热滤镜会将图像转换为“热图”&#xff0c;而卡通滤镜则提供生动的图像&#xff0c;这些图像看起来…

【论文复现】粘菌算法在最优经济排放调度中的发展与应用

目录 1.摘要2.黏菌算法SMA原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了一种改进粘菌算法&#xff08;ISMA&#xff09;&#xff0c;并将其应用于考虑阀点效应的单目标和双目标经济与排放调度&#xff08;EED&#xff09;问题。为提升传统粘菌算法&#xf…

C++基础(2)

目录 1. 引用 1.1 引用的概念和定义 1.2 引用的特性 1.3 引用的使用 2. 常引用 3. 指针和引用的关系 4. 内联函数inline 5. nullptr 1. 引用 1.1 引用的概念和定义 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.29 NumPy+Scikit-learn(sklearn):机器学习基石揭秘

2.29 NumPyScikit-learn&#xff1a;机器学习基石揭秘 目录 #mermaid-svg-46l4lBcsNWrqVkRd {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-46l4lBcsNWrqVkRd .error-icon{fill:#552222;}#mermaid-svg-46l4lBcsNWr…

圆上取点(例题)

Protecting The Earth &#xff08;圆内取点&#xff09; 题目描述&#xff1a; 给定 K (地球上的人数)&#xff0c;你必须制作一个保护罩来保护他们。(地球上的人数&#xff09;&#xff0c;你必须制作一个保护罩来保护他们。 已知一个人只能站在整数的坐标上&#xff0c…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.19 线性代数核武器:BLAS/LAPACK深度集成

2.19 线性代数核武器&#xff1a;BLAS/LAPACK深度集成 目录 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…