[lnsyoj110/luoguP2024]食物链
题意
原题链接
三类元素 满足 ,,。现在共有 个元素,给出 条关系 或 与 种类相同,输出非法或与前面所属关系相矛盾的关系数量
sol
并查集可以处理“朋友的朋友是朋友”这样的传递关系,却不能处理“敌人的敌人是朋友”这样的传递关系。因此,我们需要使用种类并查集(两种元素的种类并查集又被称为 friend-enemy 并查集)。种类并查集本质是并查集的拓展应用,因此基本操作与并查集相同
对于本题,需要先设计种类。由于每类元素都可能出现同类、、三种情况,因此 1
为同类,2
为 ,3
为 。
注意:种类并查集中的种类是相对于两元素间的关系而言,而非元素的种类
查询两元素关系
显然,如果两个元素不在一个并查集中,它们之间也就没有关系。反之,如果两个元素在一个并查集中,就说明两者之间的关系即为两者在并查集中的种类间的关系。
因此,要判断同类,只需要判断 即可,另外两种关系同理
连接元素
(连接元素前需要先查询关系来判断矛盾和非法的关系)
若两元素是同类,由于不知道这两个元素是什么种类,因此需要在每个种类中都将两元素连接;若两元素关系为 ,与上同理,将三个种类都进行连接
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 150005;
int fa[N];
int n, m;
int find(int x){
if (x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
void merge(int x, int y){
int fx = find(x), fy = find(y);
if (fx == fy) return ;
fa[fy] = fx;
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= 3 * n; i ++ ) fa[i] = i;
int cnt = 0;
while (m -- ){
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (x > n || y > n || x == y && op == 2) {
cnt ++ ;
continue;
}
if (op == 1){
if (find(x + n) == find(y) || find(x + 2 * n) == find(y)){
cnt ++ ;
continue;
}
merge(x, y), merge(x + n, y + n), merge(x + 2 * n, y + 2 * n);
}
else {
if (find(x) == find(y) || find(x + n) == find(y)){
cnt ++ ;
continue;
}
merge(x, y + n), merge(x + n, y + 2 * n), merge(x + 2 * n, y);
}
}
printf("%d\n", cnt);
return 0;
}
分类:
题解 / 2024训练
标签:
数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现