(1182)POJ

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值