
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B,B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是“1 X Y”,表示X和Y是同类。
第二种说法是“2 X Y”,表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1≤N≤50,000)和K句话(0≤K≤100,000),输出假话的总数。
题目
- 原题地址:食物链
- 题目编号:NC16884
- 题目类型:扩展域并查集、带权并查集
- 时间限制:C/C++ 3秒,其他语言6秒
- 空间限制:C/C++ 65536K,其他语言131072K
1.题目大意
- 懒得概括了,直接上题面:
- 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B,B吃C,C吃A。
- 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
- 有人用两种说法对这N个动物所构成的食物链关系进行描述:
- 第一种说法是“1 X Y”,表示X和Y是同类。
- 第二种说法是“2 X Y”,表示X吃Y。
- 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
- 1) 当前的话与前面的某些真的话冲突,就是假话;
- 2) 当前的话中X或Y比N大,就是假话;
- 3) 当前的话表示X吃X,就是假话。
- 你的任务是根据给定的N(1≤N≤50,000)和K句话(0≤K≤100,000),输出假话的总数。
2.题目分析
- 学到了一个不错的函数:
iota
iota(p, p + n + 1, 0):将p[0]、p[1]、... 、p[n]依次赋值为0、1、... 、n。
- 看题解说有两种做法,开三倍空间的扩展域并查集就不学了,带权并查集性能更好一些
- 取余三还不是很能理解,先保留个空
3.题目代码
#include <bits/stdc++.h>
using namespace std;
int a[50004], b[50004];
int find(int x) { return a[x]==x?x:(a[0]=find(a[x]),b[x]+=b[a[x]],a[x]=a[0]);}
int main() {
int n, k, t, x, y, xx, yy, ans=0;
cin >> n >> k;
iota(a, a+n+1, 0);
while(k--) {
cin >> t >> x >> y, t--;
if(x>n||y>n) ans++;
else {
xx = find(x), yy = find(y);
if(xx==yy) {if((b[x]-b[y]-t)%3) ans++;}
else a[xx] = yy, b[xx] = b[y] - b[x] + t;
}
}
cout << ans << endl;
}