POJ 1182 食物链 [并查集 带权并查集 开拓思路]

P - 食物链
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u
Appoint description: 

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 }

 

posted on 2015-01-30 22:13  njczy2010  阅读(149)  评论(0编辑  收藏  举报