动物王国中有三类动物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和K句话,输出假话的总数。
输入格式
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
输出格式
只有一个整数,表示假话的数目。
数据范围
1≤N≤50000,
0≤K≤100000
输入样例:
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
输出样例:
3
首先,查看输入,k行询问,每次说明两只动物x,y的关系。
其次,查看一句话如何才能是假话
①当前的话中X或Y比N大,就是假话,这个判断起来最简单,只需要if(x>n || y>n) ans++;
即可。
②当前的话和之前真话冲突或者出现x吃x就是假话,其实出现了x吃x就是和真话冲突。
故我们可以将可以确定正确关系的所有动物放在一个集合当中,初始的时候我们只知道每个动物不吃自己,所以每个动物各成集合。
其次在一个集合当中,我们需要维护当前节点到此集合根节点的距离d[i]
,因为只有三种动物,所以每个动物所属的种类可以用kind[i] = d[i]%3
表示一个确定的集合当中动物的状态关系,可以令kind = 1吃0,2吃1,0吃2,所以当kind[i]%3 == kind[j]%3
时i和j为同一物种,kind[i]%3 == kind[j]%3
时表示i吃j。
既然是对集合的合并和查询,当然就要用到并查集,只是需要维护一个距离参数而已。
当询问的一句话的两个物种不在同一个集合的时候,说明两个动物关系未定,当前的话就是真话,没有发生冲突,根据当前的话合并两个集合。
有关距离的更新
if(x和y同类)
(d[sy]+d[y])%3 = d[x]%3
即d[sy] = (d[x]%3+d[y]%3+3)%3
if(x吃y)
d[x]%3 = (d[sy] +d[y]+1)%3
d[sy] = (d[x]%3-d[y]%3-1+3)
当询问的两个物种在同一个集合的时候,有可能和真话发生冲突。
非冲突状态
同类:d[x] %3 == d[y]%3
x吃y: d[x]%3 == (d[y]+1)%3
#include
#include
using namespace std;
const int N = 5e4+10;
int n, k;
int p[N], d[N];//p是并查集的集合,d[i]是i到根节点的距离
//带有路径压缩的并查集查找
int find(int x) {
if(x != p[x]) {
int t = p[x];
p[x] = find(p[x]);
d[x] += d[t];//将整个路径的距离加在一起就是当前节点到根节点的距离
}
return p[x];
}
int main() {
cin>>n>>k;
//初始化集合
for(int i = 1; i < n; ++i) {
p[i] = i;
}
int ans= 0;
while(k--) {
int D, x, y;
scanf("%d%d%d", &D, &x, &y);
if(x > n || y > n) {
ans++;
continue;
}
int sx = find(x);
int sy = find(y);
//只有在同一个集合才有可能冲突
if(sx == sy) {
//int dif = (d[x]%3 - d[y]%3 + 3)%3;
if(D == 1) {
if(d[x]%3 != d[y]%3) {
ans++;
}
}
else {
if(d[x]%3!= (d[y]+1)%3) {
ans++;
}
}
}
else{
//不会冲突,合并两个集合
p[sy] = sx;
//1-->0, 2-->1, 3-->2
//(d[y]+d[sy])%3 = d[x]%3
//d[sy] = d[x]-d[y];
if(D == 1) {
d[sy] = (d[x]%3-d[y]%3+3)%3;
}
else{
//(d[y]+d[sy])%3-d[x]%3 = 1
d[sy] = (d[x]%3-d[y]%3-1+3)%3;
}
}
}
cout<<ans<<endl;
return 0;
}