NOI2001 食物链
地址:https://www.luogu.com.cn/problem/P2024
算法分类:并查集、加权
题目原文
食物链
Problem Description
动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B 吃 C,C 吃 A。
现有 N (1 ≤ N ≤ 5 ∗ 10^4)个动物,以 1 - N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这 N 个动物所构成的食物链关系进行描述:
-
第一种说法是 1 X Y,表示 X 和 Y 是同类。
-
第二种说法是2 X Y,表示 X 吃 Y 。
此人对 N 个动物,用上述两种说法,一句接一句地说出 K(1 ≤ K ≤ 10^5)句话,这 K 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
-
当前的话与前面的某些真的话冲突,就是假话
-
当前的话中 X 或 Y 比 N 大,就是假话
-
当前的话表示 X 吃 X,就是假话
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
Input
第一行两个整数,N,K,表示有 N 个动物,K 句话。
第二行开始每行一句话(按照题目要求,见样例)
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
题目分析
一共有三种群体A,B,C,我们可以用并查集表示和维护。
同时,为了表示他们三者的关系:A吃B,B吃C,C吃A。即A的猎物是B,A的天敌是C。那么,我们就可以在 区间表示自身及同类,区间表示它对应的猎物,区间表示它的天敌。
那么,如果要判断u与v的是否为u吃v的关系,我们只需看u与v+N是否有相同祖先即可。需要注意的是,如果要表示u与v同类的关系,那么我们不仅要合并自身与,还要合并他们的猎物与和天敌与。
同理,判断或表示其他关系时也应比较或合并多项。
程序代码
1 #include <iostream> 2 #include <stdio.h> 3 4 using namespace std; 5 const int maxn=50005; 6 int N, K; 7 int e, u, v; 8 int tot; 9 int f[maxn*3]; 10 inline int read(){ //读入优化 11 int x=0, f=1; 12 int c=getchar(); 13 while(!isdigit(c)){ 14 f=c=='-'?-1:1; 15 c=getchar(); 16 } 17 while(isdigit(c)){ 18 x=(x<<1)+(x<<3)+(c^48); 19 c=getchar(); 20 } 21 return f*x; 22 } 23 inline int find(int x) 24 { 25 return x==f[x]?x:f[x]=find(f[x]); 26 } 27 int main() 28 { 29 //cin>>N>>K; 30 N=read(); 31 K=read(); 32 for(int i=0;i<=N*3;i++)f[i]=i;//初始化 33 while(K--) 34 { 35 //cin>>e>>u>>v; 36 e=read(); 37 u=read(); 38 v=read(); 39 if(u>N||v>N){//不合法情况 40 tot++; 41 continue; 42 } 43 if(e==1)//uv同类 44 { 45 if(find(u+N)==find(v)||find(v)==find(u+2*N))//u吃v或v吃u 46 { 47 tot++; 48 continue; 49 } 50 f[find(u)]=f[find(v)];//自身同类 51 f[find(u+N)]=f[find(v+N)];//猎物同类 52 f[find(u+2*N)]=f[find(v+2*N)];//天敌同类 53 } 54 else//u吃v 55 { 56 if(u==v||find(u)==find(v)||find(u+2*N)==find(v)){//u与v同类或v吃u 57 tot++; 58 continue; 59 } 60 f[find(u)]=f[find(v+2*N)];//u是v的天敌 61 f[find(u+N)]=f[find(v)];//u的猎物是v 62 f[find(u+2*N)]=f[find(v+N)];//u的天敌是v的猎物 63 } 64 } 65 cout<<tot<<endl; 66 //system("pause"); 67 return 0; 68 }