并查集

并查集

并查集朴素实现:

inline ll find(ll x)
{
      if(fa[x]==x) return x;
      return find(fa[x]);
}

路径压缩

inline ll find(ll x)
{
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}

在朴素实现的过程中,复杂度较高,而路径压缩的复杂度为 \(O(α(n))\) ,可近似认为其复杂度为常数级别

但是路径压缩的做法是把所有的子节点都直接与根节点相连,会破坏树的原始结构

拓展域

对于多种关系的处理,我们可以将其合并范围增大,以表示不同的合并关系

\(1\) ~ \(n\) 范围表示A类,\(n+1\) ~ \(2n\) 范围表示B类,\(2n+1\) ~ \(3n\) 范围表示C类
之后按照题目的食物链关系合并即可

code

#include<iostream>
#include<cstdio>
#include<math.h>
#include<cstring>
#include<algorithm>
#define ll long long

const ll maxn=5e4+10;
ll fa[3*maxn];
ll n,k,a,b,ans;

inline ll find(ll x)
{
	if(fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}

int main(void)
{
	scanf("%lld %lld",&n,&k);
	
	for(int i=1;i<=n*3;i++) fa[i]=i;
	for(int i=1;i<=k;i++)
	{
		ll op,x,y;
		scanf("%lld %lld %lld",&op,&x,&y);
		
		if(x>n||y>n)
		{
			ans++;
			continue;
		}
		if(op==1)
		{
			if(find(x+n)==find(y)||find(x+n+n)==find(y)) ans++;
			else
			{
				fa[find(x)]=find(y);//同类 
				fa[find(x+n)]=find(y+n);//同类 
				fa[find(x+n+n)]=find(y+n+n);//同类 
			}
		}
		if(op==2)
		{
			if(x==y)
			{
				ans++;
				continue;
			}
			if(find(x)==find(y)||find(x)==find(y+n+n)) ans++;
			else
			{
				fa[find(x+n)]=find(y+n+n);//B->C
				fa[find(x)]=find(y+n);//A->B
				fa[find(x+n+n)]=find(y);//C->A
			}
		}
	}
	
	printf("%lld\n",ans);
	
	return 0;
}

边带权

即在路径压缩的基础上,在进行合并之前,先对边权进行一些处理,之后再进行合并的操作

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

const ll maxn=3e4+10;
ll t,x,y;
char op;
ll fa[maxn],dis[maxn],siz[maxn];

inline ll find(ll x)
{
	if(fa[x]==x) return x;
	ll rot=find(fa[x]);
	dis[x]+=dis[fa[x]];
	return fa[x]=rot;
} 

inline void upd(ll x,ll y)
{
	ll ex=find(x),ey=find(y);
	fa[ex]=ey;
	dis[ex]=siz[ey];
	siz[ey]+=siz[ex];
}

int main(void)
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	for(int i=1;i<=maxn;i++) fa[i]=i,siz[i]=1;
	memset(dis,0,sizeof(dis));
	
	cin>>t;
	
	while(t--)
	{
		cin>>op>>x>>y;
		
		if(op=='M')
		{
			upd(x,y);
		}
		if(op=='C')
		{
			ll ex=find(x),ey=find(y);
			if(ex!=ey)
			{
				cout<<"-1"<<'\n';
				continue;
			}
			else
			{
				if(x==y)
				{
					cout<<"0"<<'\n';
					continue;
				}
				cout<<abs(dis[x]-dis[y])-1<<'\n';
			}
		}
	}
	
	return 0;
}
posted @ 2020-12-04 11:16  雾隐  阅读(94)  评论(0编辑  收藏  举报