动物王国中有三类动物 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 ≤ N ≤ 5 ∗ 10^4
1 ≤ K ≤ 10^5
好题啊好题啊(啪啪啪)!干了我一天终于出来了。
一开始想用边带权并查集解,发现本蒟蒻想不出来,还是用了扩展域。
这题可以看作 P1525 关押罪犯 的一个延伸拓展题目,具体思路是差不多的。
如果对扩展域有疑问,可以看我以前的一篇题解 P1525 关押罪犯[扩展域并查集],里面有提到扩展域。
思路:
扩展域并查集维护三个域:x_self同类,x_enemy天敌,x_eat捕食。
他们之间的关系:
假设有x,y两个动物,
如果题目给定x和y是同类,那么合并x_self,y_self和x_enemy,y_enemy和x_eat和y_eat。
前提条件是:x_self与y_eat不在同一个集合,x_eat与y_self不在同一个集合。
如果题目给定x吃y,这里我们注意到一点,由于题目给出的食物链关系是环形,因此我们可以由“x吃y”推断出“x的天敌是y的猎物”。
由此得到,合并x_eat,y_self和x_self,y_enemy和x_enemy,y_eat。
前提条件是:x_self和y_self不在一个集合,x_self和y_eat不在一个集合。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #include<iostream> 6 #define N 50010 7 using namespace std; 8 struct node{ 9 int x,y,flag; 10 }g[N<<4]; 11 int n,k,fa[N<<4]; 12 int get(int x) 13 { 14 if(fa[x]==x) return x; 15 return fa[x]=get(fa[x]); 16 } 17 void merge(int x,int y) 18 { 19 x=get(x),y=get(y); 20 fa[x]=y; 21 } 22 int main() 23 { 24 //freopen("fuc.in","r",stdin); 25 //freopen("fuc.out","w",stdout); 26 int cnt=0; 27 scanf("%d%d",&n,&k); 28 for(int i=1;i<=n*3;i++) fa[i]=i; 29 for(int i=1;i<=k;i++) 30 scanf("%d%d%d",&g[i].flag,&g[i].x,&g[i].y); 31 for(int i=1;i<=k;i++){ 32 if(g[i].x>n||g[i].y>n){ 33 cnt++;continue; 34 } 35 int x_self=g[i].x,x_enemy=g[i].x+n,x_eat=g[i].x+n+n; 36 int y_self=g[i].y,y_enemy=g[i].y+n,y_eat=g[i].y+n+n; 37 if(g[i].flag==1){ 38 if(get(x_eat)==get(y_self)||get(x_self)==get(y_eat)){ 39 cnt++; 40 } 41 else{ 42 merge(x_self,y_self); 43 merge(x_eat,y_eat); 44 merge(x_enemy,y_enemy); 45 } 46 } 47 else{ 48 if(get(x_self)==get(y_self)||get(y_eat)==get(x_self)){ 49 cnt++; 50 } 51 else{ 52 merge(x_self,y_enemy); 53 merge(x_eat,y_self); 54 merge(x_enemy,y_eat); 55 } 56 } 57 } 58 cout<<cnt<<endl; 59 return 0; 60 }
原文:https://www.cnblogs.com/DarkValkyrie/p/10979331.html