240. 食物链

题目链接

240. 食物链

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

ABBCCA

现有 N 个动物,以 1N 编号。

每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。

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

第一种说法是 1 X Y,表示 XY 是同类。

第二种说法是 2 X Y,表示 XY

此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。

当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

  1. 当前的话与前面的某些真的话冲突,就是假话;
  2. 当前的话中 XYN 大,就是假话;
  3. 当前的话表示 XX,就是假话。

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

输入格式

第一行是两个整数 NK,以一个空格分隔。

以下 K 行每行是三个正整数 DXY,两数之间用一个空格隔开,其中 D 表示说法的种类。

D=1,则表示 XY 是同类。

D=2,则表示 XY

输出格式

只有一个整数,表示假话的数目。

数据范围

1N50000,
0K100000

输入样例:

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

输出样例:

3

解题思路

扩展域并查集

对于一个点可以拆分为三类:同类、天敌类、捕食类,这三种关系都是互斥的关系,即对于 x 来说,把与 x 同类的放在一个集合,天敌类放在一个集合,捕食类放在一个集合,现在并查集主要维护这些信息,即对于 x 来说,如果 xy 属于同一类,则将 xy 的同类、天敌类、捕食类分别放在一个集合里面,否则如果 xy,则分别将将 x 的捕食类跟 yx 的天敌类和 y 的捕食类,xy 的天敌类放在一个集合里
另外,判断出现矛盾的情况:

  • xy 属于同一类

    • xy
    • yx
  • xy

    • xy 属于同一类
    • yx
  • 时间复杂度:O(n)

带边权并查集

对于 (x,y),考虑定义并查集树边权,如果 yx 的父亲节点,说明 x 可以吃 y,判断 x 跟并查集树根节点 rt[x] 的关系,如果 x 到根节点 rt[x] 的距离 d[x]%3=0 说明 xrt[x] 是同类,如果 d[x]%3=1 说明 xrt[x],否则说明 rt[x]x
所以并查集合并时要维护这样的信息,当合并时,只需要将需要变化的值加在根节点变化的根节点上,下次查询时所有的 d[x] 都要加上这样的变化值,注意路径压缩时,当一个根节点被赋予值时,说明树中的所有 d[x] 都要加上该变化值,故d[x] 应该加上的是 d[fa[x]] 而不是直接 rt[x]
另外:取模可能会出现负数,即不一定有 a%3b%3 等价于 (ab)%3,因为负数取模是先取模再加上负号

  • 时间复杂度:O(n)

代码

  • 扩展域并查集
// Problem: 食物链 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/242/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=50005*3; int n,k,fa[N]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=3*n;i++)fa[i]=i; int res=0; while(k--) { int d,x,y; scanf("%d%d%d",&d,&x,&y); if(x>n||y>n) { res++; continue; } if(d==1) { if(find(x+2*n)==find(y))res++; else if(find(y+2*n)==find(x))res++; else fa[find(x)]=find(y),fa[find(x+n)]=find(y+n),fa[find(x+2*n)]=find(y+2*n); } else { if(x==y) { res++; continue; } if(find(x)==find(y))res++; else if(find(y+2*n)==find(x))res++; else fa[find(y)]=find(x+2*n),fa[find(y+2*n)]=find(x+n),fa[find(x)]=find(y+n); } } printf("%d",res); return 0; }
  • 带边权并查集
// Problem: 食物链 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/242/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=50005; int n,k,fa[N],d[N]; int find(int x) { if(x==fa[x])return x; int t=find(fa[x]); d[x]+=d[fa[x]]; return fa[x]=t; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)fa[i]=i; int res=0; while(k--) { int op,x,y; scanf("%d%d%d",&op,&x,&y); if(x>n||y>n) { res++; continue; } int px=find(x),py=find(y); if(op==1) { if(px==py&&(d[x]-d[y])%3)res++; else if(px!=py) { fa[px]=py; d[px]=d[y]-d[x]; } } else { if(x==y) { res++; continue; } if(px==py&&(d[x]-d[y]-1)%3)res++; else if(px!=py) { fa[px]=py; d[px]=d[y]-d[x]+1; } } } printf("%d",res); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16935515.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(268)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示