#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<stack>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#define ll __int64
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0xfffffff
#define mod 1000000007
using namespace std;
/*
题型:并查集
想法:这个应该是并查集的经典题目了,今天特地学一下。。
看着飘过小妞的博客,一点一点来吧
偏移量:number - 1
x->y 偏移量0时 x和y同类
x->y 偏移量1时 x被y吃
x->y 偏移量2时 x吃y
PS:单组输入数据
*/
struct node
{
int parent; //p[i].parent表示节点i的父节点
int relation; //p[i].relation表示节点i与其父节点(即p[i].parent)的关系
} p[MAX];
void init(int n)
{
int i;
for(i = 1; i<=n; i++)
{
p[i].parent = i;
p[i].relation = 0;
/*
0 代表跟父亲节点是同类
1 代表节点被当前根结点吃
2 代表节点吃当前根结点
*/
}
}
int Find(int x)
{
int temp;
if(x==p[x].parent)
{
return x;
}
temp = p[x].parent;
p[x].parent = Find(temp);
p[x].relation = (p[x].relation + p[temp].relation) % 3;
//为什么这个公式是正确的呢?请看小牛的博客,用的是一种向量的思想··
//http://blog.csdn.net/niushuai666/article/details/6981689
return p[x].parent;
}
int main()
{
int n,m;
int sum;
int a,b,number;
scanf("%d%d",&n,&m);
sum = 0;
init(n);
for(int i = 1; i<=m; i++)
{
scanf("%d%d%d",&number,&a,&b);
if(a>n||b>n)
{
sum++;
continue;
}
if(number==2&&a==b)
{
sum++;
continue;
}
int xx = Find(a);
int yy = Find(b);
if(xx!=yy)
{
p[yy].parent = xx;
p[yy].relation = (p[a].relation + (number - 1) + 3 - p[b].relation)%3;
/*
关系域更新
当不属于一个集合时 rootx->rooty = rootx->x + x->y + y->rooty
x->y的偏移值为d-1
rootx->x的偏移量为 p[x].relation
y->rooty的偏移量为 3 - p[y].relation
*/
}
else
{
if(number==1&&p[a].relation!=p[b].relation)
{
sum++;
continue;
}
if(number==2&&(3 - p[a].relation + p[b].relation)%3!=number-1)
{
sum++;
continue;
}
/*
关系域更新
当xx和yy属于同一集合是的时候
我们验证x->y之间的偏移量是否与题中给出的d-1一致
rootx = rooty
x->y = x->rootx + rooty->y
x->y = (3-relation[x]+relation[y])%3,
*/
}
}
printf("%d\n",sum);
return 0;
}
#include<cstdio>
#include<string.h>
#include<string>
#include<stack>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#define ll __int64
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0xfffffff
#define mod 1000000007
using namespace std;
/*
题型:并查集
想法:这个应该是并查集的经典题目了,今天特地学一下。。
看着飘过小妞的博客,一点一点来吧
偏移量:number - 1
x->y 偏移量0时 x和y同类
x->y 偏移量1时 x被y吃
x->y 偏移量2时 x吃y
PS:单组输入数据
*/
struct node
{
int parent; //p[i].parent表示节点i的父节点
int relation; //p[i].relation表示节点i与其父节点(即p[i].parent)的关系
} p[MAX];
void init(int n)
{
int i;
for(i = 1; i<=n; i++)
{
p[i].parent = i;
p[i].relation = 0;
/*
0 代表跟父亲节点是同类
1 代表节点被当前根结点吃
2 代表节点吃当前根结点
*/
}
}
int Find(int x)
{
int temp;
if(x==p[x].parent)
{
return x;
}
temp = p[x].parent;
p[x].parent = Find(temp);
p[x].relation = (p[x].relation + p[temp].relation) % 3;
//为什么这个公式是正确的呢?请看小牛的博客,用的是一种向量的思想··
//http://blog.csdn.net/niushuai666/article/details/6981689
return p[x].parent;
}
int main()
{
int n,m;
int sum;
int a,b,number;
scanf("%d%d",&n,&m);
sum = 0;
init(n);
for(int i = 1; i<=m; i++)
{
scanf("%d%d%d",&number,&a,&b);
if(a>n||b>n)
{
sum++;
continue;
}
if(number==2&&a==b)
{
sum++;
continue;
}
int xx = Find(a);
int yy = Find(b);
if(xx!=yy)
{
p[yy].parent = xx;
p[yy].relation = (p[a].relation + (number - 1) + 3 - p[b].relation)%3;
/*
关系域更新
当不属于一个集合时 rootx->rooty = rootx->x + x->y + y->rooty
x->y的偏移值为d-1
rootx->x的偏移量为 p[x].relation
y->rooty的偏移量为 3 - p[y].relation
*/
}
else
{
if(number==1&&p[a].relation!=p[b].relation)
{
sum++;
continue;
}
if(number==2&&(3 - p[a].relation + p[b].relation)%3!=number-1)
{
sum++;
continue;
}
/*
关系域更新
当xx和yy属于同一集合是的时候
我们验证x->y之间的偏移量是否与题中给出的d-1一致
rootx = rooty
x->y = x->rootx + rooty->y
x->y = (3-relation[x]+relation[y])%3,
*/
}
}
printf("%d\n",sum);
return 0;
}