题目描述
安徽省芜湖市第二十七中学测试题
NOI 2001 食物链(eat)
Description:Official
Data:Official
Program:JackDavid127
动物王国中有三类动物 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),输出假话的总数。
输入格式
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数D,X,Y,两数之间用一个空格隔开,其中 D 表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
输出格式
只有一个整数,表示假话的数目。
样例输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
样例输出
3
提示
输入文件 对7句话的分析
100 7
1 101 1 假话
2 1 2 真话
2 2 3 真话
2 3 3 假话
1 1 3 假话
2 3 1 真话
1 5 5 真话
并查集
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int maxx = 2102105;
int w[600105];
int b[2102105];
int n,m,r,k,t,num,now,p;
const double pi=acos(-1.0);
int find(int x)
{
if(w[x] == x)
{
return x;
}
else
{
return w[x] = find(w[x]);
}
}
void check(int a ,int b)
{
a = find(w[a]);
b = find(w[b]);
if(a != b)
{
w[a] = b;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n * 3; i ++)//n:同类域// 2n:吃对方域//3n:被吃域
{
w[i] = i;
}
int ans = 0;
for(int i = 1; i <= m; i ++)
{
int a, b, c;
cin >> a >> b >> c;
if(b > n||c > n)
{
ans ++;
continue;
}
if(a == 1)//同类
{
if(find(b) == find(c + n)||find(b + n) == find(c))//b捕食域和c同类域同一集合(b吃c
{//或者 (c吃b
ans ++;
}
else
{
check(b , c);//1.不吃
check(b + n , c + n);//2.不会被吃
check(b + 2 * n , c + n * 2);//2.也不会被c吃的动物吃掉
}
}
else//b吃c
{
if(find(b) == find(c) || b == c || find(b) == find(c + n))//当 b被c吃或者bc同类
{
ans ++;
}
else
{
check(b + n , c);//1.b吃c
check(b + n * 2 , c + n);//2.b被c吃的动物吃了
check(b, c + 2 * n );//3.c被b吃
}
}
}
cout<< ans << endl;
return 0;
}
加权写法
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxx = 1000050;
int n, m, k, t,now, p;
const double pi = acos(-1.0);
int fa[1000050], w[1000050];
int find(int x)
{
if (fa[x] == x)
{
return x;
}
else
{
int s = fa[x];
fa[x] = find(fa[x]);
w[x] += w[s];
return fa[x];
}
}
void check(int x, int y, int q)
{
int x1 = find(x);
int y1 = find(y);
if (x1 != y1)
{
fa[x1] = y1;
w[x1] = q + w[y] - w[x];//x 和 的距离
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
fa[i] = i;
w[i] = 0;
}
int ans = 0;
for (int i = 1; i <= m; i++)
{
int c, a, b;
cin >> c >> a >> b;
c--;
if (a > n|| b > n)
{
ans++;
continue;
}
if (find(a) == find(b))
{
int was = w[a] - w[b];
was = (was % 3 + 3) % 3;
if (was != c)//如果其得出的结论和以前的结论冲突了
{
ans++;
continue;
}
}
else
{
check(a, b, c);
}
}
cout << ans << endl;
return 0;
}