【笔记】带权并查集

126 阅读1分钟

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战.


带权并查集的每个节点除了记录fa外,还记录一个val,表示与根节点的差值。 find过程中,需要更新val,加上原来父亲的val,注意原来的父亲需要存储在临时变量中,不然会被覆盖。 join过程中,依旧是对两个根建立父子关系,设新关系为a-b=s,且令fa[ra]=rb,那么val[ra] = v-val[a]+val[b].

struct UFS
{
	int fa[M], val[M]; //val表示比根高多少分
	void init(int n)
	{
		for(int i=1; i<=n; ++i)
			fa[i] = i, val[i] = 0;
	}
	int find(int n)
	{
		if(fa[n]==n) return n;
		int tmp = fa[n];
		fa[n] = find(tmp);
		val[n] += val[tmp];
		return fa[n];
	}
	// a-b=v
	// (a-val[a]) - (b-val[b]) = v-val[a]+val[b];
	void join(int a, int b, int v) //a比b高v
	{
		int ra=find(a), rb=find(b);
		fa[ra] = rb;
		val[ra] = v-val[a]+val[b];
	}
}ufs;

hihocoder #1515 : 分数调查

/* LittleFall : Hello! */
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int n = read(), m = read(), q = read();
	ufs.init(n);
	for(int i=1; i<=m; ++i)
	{
		int x = read(), y = read(), s = read();
		//printf("join %d %d %d\n",x,y,s );
		ufs.join(x, y, s);
		// for(int i=1; i<=n; ++i)
		// {
		// 	ufs.find(i);
		// 	printf("%d %d\n",ufs.fa[i],ufs.val[i] );
		// }
	}
	for(int i=1; i<=q; ++i)
	{
		int x = read(), y = read();
		if(ufs.find(x)==ufs.find(y))
		{
			printf("%d\n",ufs.val[x]-ufs.val[y] );
		}
		else
		{
			printf("-1\n");
		}
	}


    return 0;
}


inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

考虑带权并查集,此时的权值表示与根节点的关系:0表示同类,1表示吃根节点,2表示被根节点吃。

那么:当前节点到根节点的关系 = (当前节点到父节点的关系 + 父节点到根节点的关系) % 3

节点A到节点B的关系 = (A到根的关系 - B到根的关系)% 3,前提是A和B在一个连通块中。

int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int n = read(), q = read(), ans = 0;
	ufs.init(n);
	while(q--)
	{
		int op = read(), x = read(), y = read();
		if(x>n || y>n) ++ans;
		else if(op==1)
		{
			if(ufs.find(x)==ufs.find(y) && ufs.val[x]!=ufs.val[y])
				++ans;
			else
				ufs.join(x, y, 0);
		}
		else 
		{
			if(ufs.find(x)==ufs.find(y) && (ufs.val[x]-ufs.val[y]+3)%3!=1)
				++ans;
			else
				ufs.join(x, y, 1);
		}
	}
	printf("%d\n",ans );

    return 0;
}

本文也发表于我的 csdn 博客中。