带权并查集详解加例题----洛谷P1196 [NOI2002]银河英雄传说

首先介绍一下什么是带权并查集
带权故名思意,在一个集合中,集合之间两两距离为权值,它与普通的的并查集主要差在find函数上
对比
普通

int find(int x)
{
 if(f[x]!=x)
 f[x]=find(f[x]);
 return f[x];
}

带权

int find(int x)
{
	if(fa[x].fa != x)
	 { 
	 int t=fa[x].fa;
	 fa[x].fa = find(fa[x].fa);
	 fa[x].wz+=fa[t].wz;
	  } 
	return fa[x].fa;   
}

fa[x].wz+=fa[t].wz;很显然他们之间的差别在这
这句话的意思是x这个数在集合中的位置是它本身的位置加上它父亲所在的位置。
可能有的朋友会问,那岂不是每一次find查找都会进行一次加,然后x的位置随着每一次find不断增加,这不对了,这就说明我们对并查集find的这个函数理解不够。
并查集可以类似看成多叉数,它们在每一次合并时都可以看成把它和根节点相连,我们赋根位置为零,所以在第一次查找之后,每次都是它本身的位置加零(因为它父亲是根节点),位置大小并不会改变。

例题

#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
	int fa,wz,size;
};
node fa[30002];
void csh(){
	for(int i=1;i<=30001;i++)
	{fa[i].fa=i;
	 fa[i].wz=0;//位置刚开始都是零
	 fa[i].size=1;//每一个集合大小开始都为一
	}
}
int find(int x)
{
	if(fa[x].fa != x)
	 { 
	 int t=fa[x].fa;
	 fa[x].fa = find(fa[x].fa);
	  fa[x].wz+=fa[t].wz;//重点
	  } 
	return fa[x].fa;   
}
int main()
{
	csh();
	scanf("%d",&n);
	while(n--)
	{
		char command;
		cin>>command;
		int x,y;
		scanf("%d%d",&x,&y);
		int xx,yy;
		xx=find(x);
		yy=find(y);
		if(command == 'M')
		{
		fa[xx].fa=yy;
		fa[xx].wz+=fa[yy].size;//xx为x所在集合的根节点,xx距离y所在集合的根节点的距离为y集合的大小加上xx本身的位置(由于xx为根节点,本身位置为0)
		fa[yy].size+=fa[xx].size;//更新yy集合的大小
		fa[xx].size=0;//更新xx集合的大小
		continue;
		}
		if(command == 'C')
		{
		if(yy!=xx)
		printf("-1\n");
		else
		printf("%d\n",abs(fa[x].wz-fa[y].wz)-1);
	    continue;}
	}
	return 0;
 } 
发布了44 篇原创文章 · 获赞 4 · 访问量 1077

猜你喜欢

转载自blog.csdn.net/qq_44162236/article/details/102769786