食物链
动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。 A 吃 B,B
吃 C,C 吃 A。
现有 N 个动物,以 1-N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道
它到底是哪一种。
有人用两种说法对这 N 个动物所构成的食物链关系进行描述:
第一种说法是“ 1XY”,表示 X 和 Y 是同类。
第二种说法是“ 2XY”,表示 X 吃 Y 。
此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真
的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
• 当前的话与前面的某些真的话冲突,就是假话
• 当前的话中 X 或 Y 比 N 大,就是假话
• 当前的话表示 X 吃 X,就是假话
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
思路
将 A,B,C 之间的关系用三个维度来记录, 三个维度的所有变量一开始都有自己的标号,最后据题意进行合并
//#pragma comment(linker, "/STACK:102400000,102400000")
#include "bits/stdc++.h"
#define pb push_back
#define ls l,m,now<<1
#define rs m+1,r,now<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {
int x=0;
char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0', c=getchar();
return x;
}
const int maxn = 5e4+10;
const int mod = 1e9+7;
const double eps = 1e-9;
int N, K;
int a[3*maxn];
int find(int p) { return p==a[p]?p:a[p]=find(a[p]); }
void link(int pi, int pj) {
int x=find(pi);
int y=find(pj);
if(x!=y) a[x]=y;
}
int main() {
//ios::sync_with_stdio(false);
N=read(), K=read();
for(int i=1; i<=3*N; ++i) a[i]=i; //扩展域标号, 1~N表示自身,N+1~2N表示吃谁,2N+1~3N表示被谁吃
int cnt=0;
while(K--) {
int q=read(), x=read(), y=read();
if(x>N||y>N) cnt++;
else {
if(q==1) {
if(x==y) continue;
if(find(x)==find(y+N)||find(x+N)==find(y)) cnt++; //如果x吃y,或者y吃x,则不满足
else link(x,y), link(x+N,y+N), link(x+2*N,y+2*N);
}
else {
if(x==y) {
cnt++;
continue;
}
if(find(x)==find(y)||find(x+2*N)==find(y)) cnt++; //如果x与y同类或者x被y吃,则不满足
else link(x,y+2*N) ,link(x+N,y), link(x+2*N,y+N);
}
}
}
printf("%d\n", cnt);
}