带权并查集 POJ 1182 食物链

题意:

带权并查集:

初学并查集的时候不太理解带权并查集,现在感觉主要是理解一下偏移量 和 路径压缩过程中偏移量的变化,就应该很好理解带权并查集了。

首先考虑路径压缩。

int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

这样可以做到每次find后,x的祖先要么是它本身,要么是它的父亲节点,树的深度不超过2。

 

令val[u]表示节点u到父亲节点fu的偏移量,val[v]表示节点v到父亲节点fv的偏移量。

加入新的边 (u,v,w)时,若令fa[fu]=fv,则有val[fu] = val[v]+w-val[u]

上图中u到v的偏移量就为 val[u]+val[v]+w-val[u] - val[v] = w,即u到新的根节点的偏移量减去v到新的根节点的偏移量,显然与新加入的边效果是一样的。

假设此后加入新的边 (u,v1,w1)

在执行find(u)操作时,进行路径压缩,偏移量的变化其实就是把原来路径上的总偏移量都加上,形成新的偏移量

比如下图val[u]+val[v]+w-val[u]=val[v]+w,路径压缩后u到fv的偏移量就是val[v]+w。

路径压缩后连边又和起始一样了。

int find(int x){
	if(fa[x]!=x){
		int tt=fa[x];
		fa[x]=find(fa[x]);
		val[x]=val[x]+val[tt];
	}
	return fa[x];
}

本题由于三种动物形成了一个环,那么偏移量应该始终在0-2之间,即对3取模。

(吐槽:HDU有些题不提示多组数据;POJ则有很多单组数据的题,输入后可能有些奇奇怪怪的东西,用判断EOF的方式读入就会出错) 

代码:

#include<cstdio>
#include<iostream>
using namespace std;
#define ll long long
#define db double
#define m_p make_pair
#define p_b push_back
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mst(a,b) memset(a,b,sizeof(a))
const int MAXN=5e4+5;
const db eps=1e-8;
const int INF=0x3f3f3f3f;
const int mod=3;
const int seed=131;
int fa[MAXN],val[MAXN];
int n,k;
void init(int n){
	For(i,1,n) fa[i]=i,val[i]=0;
}
int find(int x){
	if(fa[x]!=x){
		int tt=fa[x];
		fa[x]=find(fa[x]);
		val[x]=(val[x]+val[tt])%mod;
	}
	return fa[x];
}
int cal(int x,int y){//计算偏移量
	return (x-y+mod)%mod;
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d %d",&n,&k);
	init(n);
	int opt,u,v,w,fu,fv,ans=0;
	For(i,1,k){
		scanf("%d %d %d",&opt,&u,&v);
		if(u>n||v>n||u<1||v<1){
			ans++;
			continue;
		}
		fu=find(u),fv=find(v),w=opt-1;//w为u到v的偏移量,恰好是操作数减1
		if(fu!=fv){
			fa[fu]=fv;
			val[fu]=(val[v]+w-val[u]+mod)%mod;
		}
		else if(fu==fv&&cal(val[u],val[v])!=w) ans++;
	}
	cout<<ans<<"\n";
    return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值