题目描述 动物王国中有三类动物 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 句话有的是真 的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 • 当前的话与前面的某些真的话冲突,就是假话 • 当前的话中 X 或 Y 比 N 大,就是假话 • 当前的话表示 X 吃 X,就是假话 你的任务是根据给定的 N 和 K 句话,输出假话的总数。 输入输出格式 输入格式: 从 eat.in 中输入数据 第一行两个整数,N,K,表示有 N 个动物,K 句话。 第二行开始每行一句话(按照题目要求,见样例) 输出格式: 输出到 eat.out 中 一行,一个整数,表示假话的总数。 输入输出样例 输入样例#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),吃(n+1~2n),和被吃(2n+1~3n),看起来每一种动物都有独立的三组,但实际上我们用并查集把它们联系在一起了。在这道题里有两个阶段:判断和构建——判断是否存在矛盾,如果不矛盾就要添加这个新的并查集的边/节点。
(顺便再把这行可爱的并查集的代码背一遍(好萌啊想捏一捏):return x==fa[x]?x:fa[x]=find(fa[x]);)
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 int fa[300010],n,k,i,ans,a,b; 6 int find(int x) 7 { 8 return x==fa[x]?x:fa[x]=find(fa[x]); 9 } 10 void link(int x,int y) 11 { 12 int k1=find(x),k2=find(y); 13 if(k1!=k2) fa[k1]=k2; 14 } 15 int main() 16 { 17 int x; 18 cin>>n>>k; 19 for(i=1;i<=3*n;++i) fa[i]=i; 20 for(i=1;i<=k;++i) 21 { 22 cin>>x>>a>>b; 23 if(a>n||b>n||(a==b&&x==2)||a<1||b<1) ans++; 24 else 25 { 26 if(x==1) 27 { 28 if(find(a+n)==find(b)||find(a+n*2)==find(b)) ans++; 29 else 30 { 31 link(a,b); 32 link(a+n,b+n); 33 link(a+2*n,b+2*n); 34 } 35 } 36 else 37 { 38 if(find(a)==find(b)||find(a+n*2)==find(b)) ans++; 39 else 40 { 41 link(a,b+2*n); 42 link(a+n,b); 43 link(a+2*n,b+n); 44 } 45 } 46 } 47 } 48 cout<<ans<<endl; 49 return 0; 50 }