动物王国中有三类动物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),输出假话的总数。
现有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。
以下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种不行的即可(指吃与被吃的关系)
2017.7.23重写版
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <queue> 8 #include <set> 9 #include <map> 10 #include <list> 11 #include <vector> 12 #include <stack> 13 #define mp make_pair 14 //#define P make_pair 15 #define MIN(a,b) (a>b?b:a) 16 //#define MAX(a,b) (a>b?a:b) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const int MAX=2e5+5; 20 const int INF=1e8+5; 21 using namespace std; 22 //const int MOD=1e9+7; 23 typedef pair<ll,int> pii; 24 const double eps=0.00000001; 25 int par[MAX]; 26 int n,k,cnt; 27 void init(int x) 28 { 29 for(int i=0;i<=3*x;i++) 30 par[i]=i; 31 } 32 int find(int x) 33 { 34 if(par[x]==x) 35 return x; 36 else 37 return par[x]=find(par[x]); 38 } 39 bool same(int x,int y) 40 { 41 x=find(x);y=find(y); 42 return x==y; 43 } 44 void unite(int x,int y) 45 { 46 x=find(x);y=find(y); 47 par[x]=y; 48 } 49 bool x_eat_y(int x,int y) 50 { 51 return same(x,y+n)||same(x+n,y+2*n)||same(x+2*n,y); 52 } 53 int d,x,y; 54 int main() 55 { 56 scanf("%d%d",&n,&k); 57 init(n); 58 for(int i=1;i<=k;i++) 59 { 60 scanf("%d%d%d",&d,&x,&y); 61 if(x>n||y>n) 62 { 63 ++cnt;continue; 64 } 65 else 66 { 67 if(d==1) 68 { 69 if(x_eat_y(x,y)||x_eat_y(y,x)) 70 { 71 ++cnt;continue; 72 } 73 else 74 { 75 unite(x,y);unite(x+n,y+n);unite(x+2*n,y+2*n); 76 } 77 } 78 else 79 { 80 if(x==y||same(x,y)||same(x+n,y+n)||same(x+2*n,y+2*n)||x_eat_y(y,x)) 81 { 82 ++cnt;continue; 83 } 84 else 85 { 86 unite(x,y+n);unite(x+n,y+2*n);unite(x+2*n,y); 87 } 88 } 89 } 90 } 91 printf("%d\n",cnt); 92 return 0; 93 }