BZOJ1529&&洛谷P3420 [POI2005]SKA-Piggy Banks

并查集的裸题

我们不难发现,若存在一些小猪比如说1->2,2->3,3->4那么我们只需要打开4,那么之前的1,2,3都能被打开,所以我们可以将钥匙看成两头猪之间的边,将两头猪合并到一个并查集里,那么这个并查集只要有一个猪被打开 ,那么整个联通块就都能打开了,所以说我们可以边读入边合并,最后数一下联通块个数就好,据说还有tarjan做法,也是统计联通块个数233,缩点之后统计有多少个入度为0的联通分量就好,我用的并查集,代码少啊233

代码

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1e6+50;
int n,fa[M],siz[M];
inline int find(int x)
{
	if (x!=fa[x]) return fa[x]=find(fa[x]);
	return x;	
} 
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}
inline void unionn(int a,int b)
{
	if (siz[a]<=siz[b]) siz[b]+=siz[a],fa[a]=b;
	else siz[a]+=siz[b],fa[b]=a;
	return ; 
}
signed main()
{
	n=read();int ans=n;
	for (int i=1;i<=n;i++)
		fa[i]=i,siz[i]=1;
	for (int i=1;i<=n;i++)
	{
		int a=read();
		int r1=find(i),r2=find(a);
		if (r1!=r2) unionn(r1,r2),ans--;
	}
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/81122970