JSK 习题:找出所有谎言(poj 1182)-并查集+偏移向量

JSK 习题:找出所有谎言(poj 1182)-并查集+偏移向量

思路:

利用带权并查集,用偏移向量表示三种关系,以此计算
利用向量表示关系,常设关系如,x对于y(x->y)的关系:
x等于y 为0
x吃y 为1
x被吃y 为2

由此可推出各种关系
fa[x]对于x的关系:3-r[x]
x对于fa[fa[x]]的关系:r[x]=(r[x]+r[fa[x]])%3
JSK 习题:找出所有谎言(poj 1182)-并查集+偏移向量
y对于x的关系:(3-r[x]+r[y])%3
y对于fx的关系:(d-1+r[x])%3
JSK 习题:找出所有谎言(poj 1182)-并查集+偏移向量
fy对于fx的关系:((d-1+r[x])%3)+3-r[y])%3

详解:http://blog.****.net/c0de4fun/article/details/7318642/
注:输入量过大应用scanf进行输入

代码:

#include <iostream>
using namespace std;
const int N=50010;
int ans=0;
int fa[N],r[N];
void init(int n)    //初始化
{
   for(int i=0;i<=n;i++)
    {
        fa[i]=i;
        r[i]=0;
    }
}
int find(int x)
{
    int fx=x;
    if(fa[x]==x)
        return x;
    else
    {
        fx=find(fa[x]);
        r[x]=(r[x]+r[fa[x]])%3;
        fa[x]=fx;
    }
    return fa[x];
}
int unite(int x,int y,int d)
{
     int fx=find(x);
     int fy=find(y);
     if(fx==fy)
     {
         if((3-r[x]+r[y])%3==d-1)
            return 1;
         else
            return 0;
     }
     else
     {
         r[fy]=((d-1+r[x])%3+3-r[y])%3;
         fa[fy]=fx;
         return 1;
     }
}

int main()
{
    int n,k;
    cin>>n>>k;
    init(n);
    for(int i=0;i<k;i++)
    {
        int d,x,y;
        cin>>d>>x>>y;
        if(x>n || y>n || (d==2 && x==y))
            ans++;
        else
        {
            if(!unite(x,y,d))
                ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}