P - 食物链
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u
Submit Status Practice POJ 1182
Appoint description:
System Crawler (2015-01-27)
Description
动物王国中有三类动物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--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<string> 12 13 #define N 50005 14 #define M 105 15 #define mod 1000000007 16 //#define p 10000007 17 #define mod2 1000000000 18 #define ll long long 19 #define LL long long 20 #define eps 1e-6 21 #define inf 100000000 22 #define maxi(a,b) (a)>(b)? (a) : (b) 23 #define mini(a,b) (a)<(b)? (a) : (b) 24 25 using namespace std; 26 27 int n,m; 28 int f[N]; 29 int r[N]; 30 int ans; 31 32 void ini() 33 { 34 ans=0; 35 int i; 36 for(i=0;i<=n;i++){ 37 f[i]=i; 38 r[i]=0; 39 } 40 } 41 42 int find(int x) 43 { 44 int fa; 45 if(f[x]!=x) 46 { 47 fa=find(f[x]); 48 r[x]=(r[x]+r[ f[x] ])%3; 49 f[x]=fa; 50 } 51 return f[x]; 52 } 53 54 void merge(int x,int y,int d) 55 { 56 int a,b; 57 a=find(x); 58 b=find(y); 59 if(a==b){ 60 return; 61 } 62 f[b]=a; 63 r[b]=(3-r[y]+r[x]+d)%3; 64 } 65 66 void solve() 67 { 68 int d,x,y; 69 int a,b; 70 int re; 71 int i; 72 for(i=1;i<=m;i++){ 73 scanf("%d%d%d",&d,&x,&y); 74 if(x>n || y>n){ 75 ans++;continue; 76 } 77 if(d==2 && x==y){ 78 ans++;continue; 79 } 80 a=find(x); 81 b=find(y); 82 re=(3-r[x]+r[y])%3; 83 if(a==b && re!=d-1){ 84 ans++;continue; 85 } 86 //printf(" i=%d\n",i); 87 merge(x,y,d-1); 88 } 89 } 90 91 void out() 92 { 93 printf("%d\n",ans); 94 } 95 96 int main() 97 { 98 //freopen("data.in","r",stdin); 99 //freopen("data.out","w",stdout); 100 //scanf("%d",&T); 101 //for(int ccnt=1;ccnt<=T;ccnt++) 102 //while(T--) 103 //while(scanf("%d%d",&n,&m)!=EOF) 104 scanf("%d%d",&n,&m); 105 { 106 ini(); 107 solve(); 108 out(); 109 } 110 return 0; 111 }
如果我们换一个思路,把1--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<string> 12 13 #define N 50005 14 #define M 105 15 #define mod 1000000007 16 //#define p 10000007 17 #define mod2 1000000000 18 #define ll long long 19 #define LL long long 20 #define eps 1e-6 21 #define inf 100000000 22 #define maxi(a,b) (a)>(b)? (a) : (b) 23 #define mini(a,b) (a)<(b)? (a) : (b) 24 25 using namespace std; 26 27 int n,m; 28 int f[3*N]; 29 int ans; 30 31 void ini() 32 { 33 ans=0; 34 int i; 35 for(i=0;i<=3*n;i++){ 36 f[i]=i; 37 } 38 } 39 40 int find(int x) 41 { 42 int fa; 43 if(f[x]!=x) 44 { 45 fa=find(f[x]); 46 f[x]=fa; 47 } 48 return f[x]; 49 } 50 51 void merge(int x,int y) 52 { 53 int a,b; 54 a=find(x); 55 b=find(y); 56 if(a==b){ 57 return; 58 } 59 f[b]=a; 60 } 61 62 void solve() 63 { 64 int d,x,y; 65 int a,b; 66 int fx,sx; 67 int i; 68 for(i=1;i<=m;i++){ 69 scanf("%d%d%d",&d,&x,&y); 70 if(x>n || y>n){ 71 ans++;continue; 72 } 73 if(d==2 && x==y){ 74 ans++;continue; 75 } 76 a=find(x); 77 b=find(y); 78 fx=find(x+n); 79 sx=find(x+2*n); 80 if(d==1){ 81 if(b==fx || b==sx){ 82 ans++;continue; 83 } 84 else{ 85 merge(x,y); 86 merge(x+n,y+n); 87 merge(x+2*n,y+2*n); 88 } 89 } 90 else{ 91 if(b==a || b==sx){ 92 ans++;continue; 93 } 94 else{ 95 merge(x+n,y); 96 merge(x+2*n,y+n); 97 merge(x,y+2*n); 98 } 99 } 100 } 101 } 102 103 void out() 104 { 105 printf("%d\n",ans); 106 } 107 108 int main() 109 { 110 //freopen("data.in","r",stdin); 111 //freopen("data.out","w",stdout); 112 //scanf("%d",&T); 113 //for(int ccnt=1;ccnt<=T;ccnt++) 114 //while(T--) 115 //while(scanf("%d%d",&n,&m)!=EOF) 116 scanf("%d%d",&n,&m); 117 { 118 ini(); 119 solve(); 120 out(); 121 } 122 return 0; 123 }