#include <stdio.h>
int father[50005];
int rank[50005];
/*
rank[x]表示father[x]与x的关系
rank[x] = 0 表示father[x]与x是同类
rank[x] = 1 表示x吃father[x]
rank[x] = 2 表示father[x]吃x
*/
void Make_Set(int x)
{
father[x] = x;
}
int Find_Set(int x)
{
int t;
if (father[x] == x) return x;
t = father[x];
father[x] = Find_Set(father[x]);
/* 因为压缩时根节点改变,必须更新father[x]与x的关系 */
rank[x] = (rank[t] + rank[x]) % 3;
/*
㈠
确定儿子与爷爷的关系:
推理:
x y
爷爷 父亲 儿子 儿子与爷爷的关系:
0 0 (x+y)%3=0
0 1 (x+y)%3=1
0 2 (x+y)%3=2
1 0 (x+y)%3=1
1 1 (x+y)%3=2
1 2 (x+y)%3=0
2 0 (x+y)%3=2
2 1 (x+y)%3=0
2 2 (x+y)%3=1
*/
return father[x];
}
void Union_Set(int a, int b, int len)
{
int ra = Find_Set(a);
int rb = Find_Set(b);
father[ra] = rb;
rank[ra] = (rank[b] +3-rank[a] + len) % 3 ;
/*
利用上述㈠的推理方法找出根与根之间的关系:
分为三步:
①len代表x与y的关系
②3-rank[a],逆推根节点与a的关系:(利用父与子的关系反推子与父的关系)
0父与子同类 (3-0)%3=0
1父吃子 (3-1)%3=2 父吃子
2子吃父 (3-2)%3=1 子吃父
③现在把ra和rb连接在一起,那么ra的父亲结点为rb,利用㈠的推理关系,我们已经知道a与b的关系len,以及a与其根节点的关系
3-rank[a],那么可以求出a的根节点与b的关系:len+3-rank[a],同理:我们已经知道了a的根节点与b的关系和b与其根节点的关系
那么可以直接求出a的根节点与b的根节点的关系。
即:rank[ra]=(rank[rb]+3-rank[a]+len)%3;
*/
}
int main()
{
int i, n, m;
int d, x, y;
int rx, ry;
int sum = 0;
scanf("%d%d", &n, &m);
for (i = 1; i <= n; i++)
{
Make_Set(i);
}
while(m--)
{
scanf("%d%d%d", &d, &x, &y);
if (x > n || y > n || (d == 2 && x == y))
{
sum++;
}
else
{
rx = Find_Set(x);
ry = Find_Set(y);
/* 若x,y同一个集合则可确定x和y的关系 */
if (rx == ry)//在一个集合里面
{
//d-1代表x和y的关系
/*
根据㈠的推理:
(rank[x]+3-rank[y])所求的关系,即:x与y的关系:
*/
if((rank[x]+3 - rank[y] ) % 3 != d - 1)
{
sum++;
}
}
/*若x,y不在同一集合确定x的根节点与y的根节点之间的关系*/
else
{
Union_Set(x, y, d - 1);
}
}
}
printf("%d\n", sum);
return 0;
}
poj1182
最新推荐文章于 2022-12-22 21:28:01 发布