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
y对于x的关系:(3-r[x]+r[y])%3
y对于fx的关系:(d-1+r[x])%3
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;
}