POJ 1182 食物链(带权并查集||种类并查集)
原创
©著作权归作者所有:来自51CTO博客作者mb62d0cd6d0f38c的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目大意
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
带权并查集思路
代表这个点与根节点的关系, 同类 吃父节点 被父节点吃
查找()
可以画图推一下
合并()
父节点相同时,关系成立的条件是
父节点不同时,合并父节点,并更新x父节点的值,
不理解怎么更新的可以画图看一下
带权并查集代码
struct node{
int fa;//父节点
int rel;//与父节点的关系 1同类 2吃父节点 3被父节点吃
}str[maxn];
int find(int x){
if(str[x].fa==x){
return x;
}
int tmp=find(str[x].fa);
str[x].rel=(str[x].rel+str[str[x].fa].rel)%3;//从祖先节点向后开始计算x的rel
return str[x].fa=tmp;//路径压缩
}
int Union(int op,int x,int y){
int fx=find(x);
int fy=find(y);
if(fx==fy){//是一样的根节点
if((str[x].rel-str[y].rel+3)%3==op-1)
return 0;//关系正确
return 1; //给出关系与上面的矛盾
}
str[fx].fa=fy;
str[fx].rel=(-str[x].rel+op-1+str[y].rel+3)%3;//更新父节点的rel
return 0;
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){//初始化
str[i].fa=i;
str[i].rel=0;
}
int ans=0;
int op,x,y;
while(k--){
scanf("%d%d%d",&op,&x,&y);
if(x==y&&op==2)
ans++;
else if(x>n||y>n)
ans++;
else
ans+=Union(op,x,y);
}
printf("%d\n",ans);
}
种类并查集思路
代表同类,代表天敌,代表食物
时:的猎物与的天敌若是一样则不能是同类,同理的猎物与的天敌一样,也不能是同类,那么这句话就是假话。若这句话是真话,就合并.
时:与在一个集合,假话,的天敌是,假话。若这句话是真话,合并。
种类并查集代码
int fa[maxn];/// x 本身 x+n 天敌 x+2n食物
int find(int x){
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
void Union(int x,int y){
fa[find(x)]=find(y);
}
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n*3;i++){
fa[i]=i;
}
int op,x,y;
int ans=0;
while(m--){
scanf("%d%d%d",&op,&x,&y);
if(x>n||y>n){
ans++;
continue;
}
/// x 本身 x+n 天敌 x+2n食物
if(op==1){//同类
if(find(x+2*n)==find(y+n)||find(x+n)==find(y+2*n)){
ans++;
}
else{
Union(x,y);
Union(x+n,y+n);
Union(x+2*n,y+2*n);
}
}
else{//x吃y
if(find(x+n)==find(y)||find(x)==find(y)){
ans++;
}
else{
Union(x+2*n,y);
Union(y+2*n,x+n);
Union(y+n,x);
}
}
}
printf("%d\n",ans);
}