【SSL】1224 &【洛谷】P2024食物链

【SSL】1224 &【洛谷】P2024食物链

Time Limit:1000MS
Memory Limit:65536K

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

输入文件 对7句话的分析
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

Hint

NOI2001

思路

很显然,对假话条件2、3的处理十分简单,只要在读入数据时作两个条件判断即可解决,题目的主要任务在于处理条件1。
从表面上看,条件1的处理似乎也没有什么难度:一个动物无非就是A,B,C三类,而A,B,C之间的食物链关系是一对一单向环形的,也就是说如果已知动物X所属种类和X、Y之间的食物链关系,就一定可以确定出动物Y的种类,同时某个动物具体属于哪一类并不影响本题的结果,而只要求它与其他动物关系的相对位置正确即可。
于是,我们不妨开3个数组A,B,C,分别记录着三种类的成员,首先假设第一句有效话中的动物X为A类,将其放入数组A,倘若Y与X同类,则把Y也放入A;若Y被X吃,则将Y放入B,如此反复操作所有的有效话,就可以确定每个动物的种类,并容易统计出假话的个数。
问题似乎已经圆满地解决了,但是,稍稍认真思考就会发现,上面的这个算法存在着重大的错误,是十分片面的。
对于一个未知属性的生物我们都采取的是定义为A类型,这样子显然是错的。
可见,这个算法只能当每一句话都可直接与此前已知的食物链建立明确关系的时候才能使用。
明确了上面这个关系,我们就不难从刚才的算法扩展出另一种算法:对于目前关系未知的动物X,我们为他新开辟一条食物链A2,B2,C2,显然,在这个新的组中,动物X所在的种类也是随意的,于是假设它在A2组,这样,所有与X的关系就可用与算法1同样的方式加入这个组中,而这个组与原先的组A1,B1,C1的关系是不确定的。如此反复,我们也可以得到组3、组4、组5……,一旦有一句话牵涉到某两个组的成员之间的食物链关系,我们就依据一定的换算规则将这两个组合并起来,以保证关系网的完整性。
通过上面的分析,并查集在本题中的运用已经呼之欲出。
一个集合有三类的元素,合并集合的时候,需要对三类元素进行合并。

代码

#include<iostream>
#include<cstdio>
using namespace std;
int f[300010];//s本身,s+n s的食物,s+n+n s的天敌 
int find(int x)//找代表值 
{
    
    
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
void merge(int x,int y)//合并
{
    
    
	f[find(x)]=find(y);
	return;
}
int main()
{
    
    
	int n,k,i,t,x,y,ans=0;
	scanf("%d%d",&n,&k);
	for(i=1;i<=3*n;f[i]=i,i++);//初始化
	for(i=1;i<=k;i++)
	{
    
    
		scanf("%d%d%d",&t,&x,&y);
		if(x>n||y>n||(t==1&&(find(x+n)==find(y)||find(x)==find(y+n)))||(t==2&&(find(x)==find(y)||find(x)==find(y+n))))
			ans++;
		else
			if(t==1)
			{
    
    
				merge(x,y);//合并 
				merge(x+n,y+n);
				merge(x+n+n,y+n+n);
			}
			else
			{
    
    
				merge(x,y+n+n);
				merge(x+n,y);
				merge(x+n+n,y+n);
			}
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46975572/article/details/113003603
今日推荐