动物王国中有三类动物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),输出假话的总数。
Input
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
Output
只有一个整数,表示假话的数目。
Sample Input
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
Sample Output
3
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 using namespace std; 10 const int MAX=5e4+5; 11 int par[MAX*3],rankk[MAX*3]; 12 void init(int n) 13 { 14 for(int i=0;i<n;i++) 15 { 16 par[i]=i; 17 rankk[i]=0; 18 } 19 } 20 int find(int x) 21 { 22 if(par[x]==x) 23 return x; 24 else 25 return par[x]=find(par[x]); 26 } 27 void unite(int x,int y) 28 { 29 x=find(x); 30 y=find(y); 31 if(x==y) 32 return; 33 if(rankk[x]<rankk[y]) 34 par[x]=y; 35 else 36 { 37 par[y]=x; 38 if(rankk[x]==rankk[y]) 39 rankk[x]++; 40 } 41 } 42 bool same(int x,int y) 43 { 44 return find(x)==find(y); 45 } 46 int n,k; 47 int an; 48 int opt,a,b; 49 int main() 50 { 51 scanf("%d%d",&n,&k); 52 init(3*n); 53 while(k--) 54 { 55 scanf("%d%d%d",&opt,&a,&b); 56 a--;b--; 57 if(a<0||b<0||a>=n||b>=n||(opt==2&&a==b)) 58 { 59 an++;continue; 60 } 61 if(opt==1) 62 { 63 if(same(a,b+2*n)||same(a+2*n,b)) 64 { 65 an++; 66 continue; 67 } 68 else 69 { 70 unite(a,b); 71 unite(a+n,b+n); 72 unite(a+2*n,b+2*n); 73 } 74 } 75 else 76 { 77 if(same(a,b)||same(a,b+2*n)) 78 { 79 an++;continue; 80 } 81 else 82 { 83 unite(a+2*n,b); 84 unite(a+n,b+2*n); 85 unite(a,b+n); 86 } 87 } 88 } 89 printf("%d\n",an); 90 }
用x,x+n,x+2*n,分别表示元素在A、B、C集合中。某两个元素在同一个树中意味他们同时发生或同时不发生。向并查集中加入元素时要把各种情况全部加入,查询是否合法时只需查询1种不行的即可(指吃与被吃的关系)
时间: 2024-10-23 04:36:29