【poj 1182】 食物链
题目描述
动物王国中有三类动物 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 句话有的是真
的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
• 当前的话与前面的某些真的话冲突,就是假话
• 当前的话中 X 或 Y 比 N 大,就是假话
• 当前的话表示 X 吃 X,就是假话
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
输入输出格式
输入格式:
第一行两个整数,N,K,表示有 N 个动物,K 句话。
第二行开始每行一句话(按照题目要求,见样例)
输出格式:
一行,一个整数,表示假话的总数。
输入输出样例
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
3
说明
1 ≤ N ≤ 5 ∗ 10^4
1 ≤ K ≤ 10^5
题解
对于每只动物i创建3个元素i-A,i-B,i-C,并用这3×N个元素建立并查集。这个并查集维护如下信息:
~ i-x表示“i属于种类x”
~ 并查集里的每一组表示组内所有元素代表的情况都同时发生或不发生。
例如,如果i-A和j-B在同一组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类
B那么i一定属于种类A。因此,对于每一条信息只需要按照下面进行操作就行了。
~ 第一种,x和y属于同一种类......合并x-A和y-A,x-B和y-B,x-C和y-C。
~ 第二种,x吃y...........................合并x-A和y-B,x-B和y-C,x-C和y-A。
不过在合并之前,需要先判断合并是否会产生矛盾。例如在第一种信息的情况下,
需要检查比如x-A和y-B或者y-C是否在同一组等信息。
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int maxn=50005; 5 const int maxm=100005; 6 int n,m;int par[maxn*3],deep[maxn*3]; //一定要乘3,在这里挂了好几次 7 int T[maxm],X[maxm],Y[maxm]; 8 void init(int n){ 9 for(int i=0;i<n;i++){ 10 par[i]=i; 11 deep[i]=0; 12 } 13 } 14 int find(int x){ 15 if(par[x]==x) return x; 16 else return par[x]=find(par[x]); 17 } 18 void unite(int x,int y){ 19 x=find(x),y=find(y); 20 if(x==y) return; 21 if(deep[x]<deep[y]) par[x]=y; 22 else{ 23 par[y]=x; 24 if(deep[x]==deep[y]) deep[x]++; 25 } 26 } 27 bool same(int x,int y){ 28 return find(x)==find(y); 29 } 30 int read(){ //cin,cout在poj上会T 31 int x=0,f=1;char ch=getchar(); 32 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 33 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 34 return x*f; 35 } 36 int main(){ 37 n=read(),m=read(); 38 for(int i=0;i<m;i++) T[i]=read(),X[i]=read(),Y[i]=read(); 39 init(n*3); 40 int ans=0; 41 for(int i=0;i<m;i++){ 42 //cin>>T[i]>>X[i]>>Y[i]; 43 int t=T[i],x=X[i]-1,y=Y[i]-1; 44 if(x<0||x>=n||y<0||y>=n){ans++;continue;} 45 if(t==1){ 46 if(same(x,y+n)||same(x,y+2*n)) ans++; 47 else{ 48 unite(x,y); 49 unite(x+n,y+n); 50 unite(x+2*n,y+2*n); 51 } 52 } 53 else{ 54 if(same(x,y)||same(x,y+2*n)) ans++; 55 else{ 56 unite(x,y+n); 57 unite(x+n,y+2*n); 58 unite(x+2*n,y); 59 } 60 } 61 } 62 printf("%d\n",ans);
63 return 0; 64 }