POJ1182 食物链 并查集

食物链
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 113794   Accepted: 34597

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

Source

 
  1 #include <cstdio>
  2 #include <iostream>
  3 
  4 
  5 using namespace std;
  6 
  7 const int max_N=50000+2;
  8 const int max_K=1e5+2;
  9 int N,K;
 10 int T[max_K],X[max_K],Y[max_K];
 11 
 12 // 并查集的实现
 13 // 三个并查集
 14 int par[max_N*3];
 15 int ranks[max_N*3];
 16 
 17 void init(int n)
 18 {
 19     for(int i=0;i<n;++i)
 20     {
 21         par[i]=i;
 22         ranks[i]=0;
 23     }
 24 }
 25 
 26 // 寻找所属的类的编号,并优化路径上的所有点
 27 int finds(int x)
 28 {
 29     if(par[x]==x)
 30     {
 31         return x;
 32     }
 33     else
 34     {
 35         // 路径压缩
 36         return par[x]=finds(par[x]);
 37     }
 38 }
 39 
 40 // 并查集合并操作
 41 void unite(int x,int y)
 42 {
 43     x=finds(x);
 44     y=finds(y);
 45 
 46     if(x==y)
 47     {
 48         return;
 49     }
 50 
 51     // 合并到深度大的那颗树
 52     if(ranks[x]<ranks[y])
 53     {
 54         par[x]=y;
 55     }
 56     else if(ranks[x]==ranks[y])
 57     {
 58         // 随意连边,这边向y连边
 59         par[x]=y;
 60         ++ ranks[y];
 61         //par[y]=x;++ranks[x];
 62     }
 63     else
 64     {
 65         par[y]=x;
 66     }
 67 }
 68 
 69 bool same(int x,int y)
 70 {
 71     return finds(x)==finds(y);
 72 }
 73 
 74 void solve()
 75 {
 76     // 错误信息数
 77     int ans=0;
 78     // 初始化并查集
 79     init(N*3);
 80 
 81     for(int i=0;i<K;++i)
 82     {
 83         int x=X[i]-1;
 84         int y=Y[i]-1;
 85 
 86         if(x<0 || x>=N || y<0 || y>=N)
 87         {
 88             ++ans;
 89             continue;
 90         }
 91 
 92         // X 与 Y 是同一类
 93         if(T[i]==1)
 94         {
 95 
 96             // 冲突的情况
 97             // 1. x吃y
 98             // 2. y吃x
 99             if(same(x,y+N) || same(y+2*N,x))
100             {
101                 ++ans;
102             }
103             else
104             {
105                 unite(x,y);
106                 unite(x+N,y+N);
107                 unite(x+2*N,y+2*N);
108             }
109         }
110         // X 吃 Y
111         else
112         {
113 
114             // 冲突的情况
115             // 1. x与y同一类
116             // 2. y吃x
117             if(same(x,y) || same(y+2*N,x))
118             {
119                 ++ans;
120             }
121             else
122             {
123                 unite(x,y+N);
124                 unite(x+N,y+2*N);
125                 unite(x+2*N,y);
126             }
127         }
128     }
129 
130 
131     printf("%d
",ans);
132 }
133 
134 int main()
135 {
136     scanf("%d %d",&N,&K);
137     for(int i=0;i<K;++i)
138     {
139         scanf("%d %d %d",&T[i],&X[i],&Y[i]);
140     }
141 
142     solve();
143 
144     return 0;
145 }
146 
147 
148 /*
149 
150 100 7
151 1 101 1
152 2 1 2
153 2 2 3
154 2 3 3
155 1 1 3
156 2 3 1
157 1 5 5
158 */
原文地址:https://www.cnblogs.com/jishuren/p/12304657.html