并查集 带边权poj1182

一道欠了很久的题目,终于解决了

之前一直以为,将父节点设置为自己然后  用  fa【i】==i 来判断是不是根节点的方式很蠢,都不能记录这个集合有多少个元素,而且搜索路径会边长,不能依据集合大小来判断是哪个集合并上哪个集合,实际上还是自己太无知,不知道有路径压缩这种东西来改变并查集的fa数组的结构。

路径压缩就是在每次  find(x) 函数执行之后 在返回根节点的时候将  fa【x】=root  这样一来就能解决搜索路径的问题,

然后再添加一个d数组, 是用于解决带边权 ,我们的权值则是一般记录此节点与父节点的关系,只要满足这个关系可以传递我们就可以模仿矢量计算来处理权值。 

  d【x】数组存储的是x节点和他的根节点的关系,在每次find 更新fa【x】的时候一起更新。

学习链接

#include<stdio.h>
#include<iostream>
#define max 50000
using namespace std;
int fa[max];
int d[max];
int find(int x){
	if(x==fa[x])  return x;
	int root =find(fa[x]);
	d[x]=(d[x]+d[fa[x]])%3;
	return fa[x]=root;
}
int main(){
 	int n,m;
 	int a,b,c,cnt=0;
 	scanf("%d%d",&n,&m);
 	for(int i=1;i<=n;i++){
 		fa[i]=i;
		d[i]=0;
	}
 	while(m--){
 		scanf("%d%d%d",&a,&b,&c);
 		if((b>n||c>n)||(a==2&&b==c)){
 			cnt++;
 			continue;
		}
		if(a==1&&b==c)
			continue;
		int bb=find(b);
 		int cc=find(c);
		if(bb==cc){
 			if(a==1&&d[b]==d[c]){
 				;
			}
			else if(a==2&&(d[b]+(3-d[c]))%3==1){
				;
			}
			else {
				cnt++;
			//	printf("%d  %d  %d  !!!\n",a,b,c);
			//	printf("%d   %d!!!\n",d[b],d[c]);
			}
		}
		else{
			fa[bb]=cc;
			d[bb]=(3-d[b]+a-1+d[c])%3;
		}	
	}
	printf("%d\n",cnt);
	return 0;
} 





 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值