谈谈关系类并查集

经典题目是食物链相信大家应该知道

偏移量可以用有向线段来解决,lhq,xzp大神都说过这个,

a->b 为1表示 a吃b

a->b 为2表示 b被a吃

a->b->c

  1    2

可以推出a与c同类

(1+2)%3=0,为同类

所以a->b反向线段为其正向线段相反数

所以可以解决掉这道题

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
const int MAXN=50007;
int vis[MAXN],f[MAXN],n,k,ans=0;
using namespace std;
int find(int num)
{
    if (f[num]!=num) 
    {
        int pa=f[num];
        f[num]=find(f[num]);
        vis[num]=(vis[num]+vis[pa])%3;
    }
    return f[num];
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        vis[i]=0,f[i]=i;
    for (int i=1;i<=k;i++)
    {
        int num,a,b;
        scanf("%d%d%d",&num,&a,&b);
        if (a>n||b>n||(n==2&&a==b)||a<1||b<1) //特别判断一下即可
        {
            ans++;
            continue;
        }
        if (num==1)
        {
            int x=find(a),y=find(b);
            if (x==y)
            {
                if (vis[a]!=vis[b]) ans++;
            }    
            else 
            {
                vis[y]=(-vis[b]+0+vis[a]+6)%3;//这是通过有向线段推出来的
                f[y]=x;
            }
        }    
        else 
        {
            int x=find(a),y=find(b);
            if (x==y)
            {
                if ((vis[a]-vis[b]+3)%3!=1) ans++;
            }
            else 
            {
                vis[y]=(-vis[b]-1+vis[a]+6)%3;//同理,相同方法推理得知
                f[y]=x;
            }
        }
    }
    cout<<ans<<endl;    
}

这是采用偏移量的方法,空间比较省,还是值得推荐的,详细纸上记录了,记录在A本上

posted @ 2017-04-20 15:50  Kaiser-  阅读(267)  评论(0编辑  收藏  举报